Fehlinitialisierung in C++ (Fehlinitialisierung in C++), Lektion, Seite 722165
https://www.purl.org/stefan_ram/pub/fehlinitialisierung_c++ (Permalink) ist die kanonische URI dieser Seite.
Stefan Ram
C++-Kurs

Fehlinitialisierung in C++ 

Die Fehlinitialisierung  (default initialization ) wird bei Definitionen ohne  Initialisierer (initializer ) durchgeführt.

Fehlinitialisierung bei fundamentalen Typen

main.cpp

#include <iostream> /* ::std::cout */
#include <ostream> /* << */

int main(){ int a; ::std::cout << a << '\n'; }

Im obigen Programm wird ein Objekt ohne Initialisierer  definiert. Dies bedeutet, daß eine Fehlinitialisierung  vorgenommen wird. (Die Bezeichnung „Fehlinitialisierung“ ergibt sich daraus, daß ein Initialisierer fehlt.) Bei den Typen »int«, »double«, »bool«, und »char« bedeutet die Vornahme einer Fehlinitialisierung bei lokalen Variablen in der Regel (in Situationen wie in dem obigen Beispiel), daß keine Initialisierung  vorgenommen wird: Wenn das zugehörige Objekt mit automatischer Lebensdauer nicht initialisiert wird, dann hat es einen unbestimmten Wert.

(Objekten mit statischer Lebensdauer werden grundsätzlich vor allen anderen Initialisierungen erst einmal 0-initialisiert.)

Fehlinitialisierung bei Klassenobjekten

Bei Klassenobjekten hängt die Zulässigkeit und die Bedeutung der Fehlinitialisierung vom Typ  des Objektes ab, also von seiner Klasse. Im Falle der Klasse »::std::string« wird eine leere Zeichenfolge  initialisiert. In der Regel kann man davon ausgehen, daß ein Klassenobjekt durch eine Fehlinitialisierung in einen zulässigen „leeren“ oder „neutralen“ Zustand gebracht wird. Es kann aber auch sein, daß eine Klasse solch eine Initialisierung gar nicht gestattet. In diesem Fall erhält man dann eine Fehlermeldung.

main.cpp

#include <iostream> /* ::std::cout */
#include <ostream> /* << */
#include <string> /* ::std::string */

using namespace ::std::literals;

int main() { ::std::string const s; ::std::cout << '>' << s << "<\n"s; }

::std::cout
><

Bei fundamentalen Objekten  ist eine Fehlinitialisierung keine Initialisierung, bei Klassenobjekten  hängt ihre Bedeutung von der Klasse  ab.

Der Konstruktor für die Fehlinitialisierung

Der Konstruktor für die Fehlinitialisierung findet sich in der Dokumentation der Klasse als ein Konstruktor, der mit leeren Klammern  aufgerufen werden könnte, falls er eine normale Funktion wäre. Wir nennen solch einen Konstruktor mit leeren Klammern auch Fehlkonstruktor. Wir finden ihn in der im folgenden auszugsweise wiedergegebenen Dokumentation der Klasse »::std::string« ganz am Anfang.

Dokumentation der Klasse »::std::string« nach C++ 2015, 21.4.2 (vereinfacht und übersetzt)
 
::std::string();
Anlegen eines leeren ::std::string-Exemplars.
 
::std::string …( ::std::initializer_list< char >l );
Anlegen eines ::std::string-Exemplars mit dem Text der Zeichen einer Initialisierungsliste
 
::std::string( ::std::string const & s );
Anlegen eines ::std::string-Exemplars mit dem Text eines anderen ::std::string-Exemplars »s«.
 
::std::string( char const * s );
Anlegen eines ::std::string-Exemplars mit dem Text einer Zeichenfolge »s«.
 
::std::string( int n, char c );
Anlegen eines ::std::string-Exemplars mit dem Text einer n-fachen Wiederholung des Zeichens »c«.
 

Manche Klassen haben keinen  Fehlkonstruktor. In diesem Fall kann man ihre Objekt dann auch nicht  fehlinitialisieren.

Es kann auch sein, daß andere Konstruktoren als der Konstruktor mit leeren Klammern für eine Fehlinitialisierung herangezogen werden. Sie kommen dann dafür in Frage, wenn sie zwar Parameter haben, aber bei einer Funktion mit denselben Parameterdeklarationen auch ein Aufruf ohne Argument erlaubt wäre.

Die Deklaration von Funktionen

Das folgende Programm zeigt einen Versuch eines Programmierers, ein Exemplar der Klasse »::std::string« mit einer Fehlinitialisierung anzulegen. In Analogie zur Direktinitialisierung mit »::std::string const s( "abc"s );« verwendet der Programmierer dazu die Schreibweise »::std::string const s();«, die eine Direktinitialisierung mit leeren runden Klammern werden soll und daher den entsprechenden Konstruktor mit leeren Klammern  verwenden soll.

main.cpp

#include <iostream> /* ::std::cout */
#include <ostream> /* << */
#include <string> /* ::std::string */

using namespace ::std::literals;

::std::string s() { return ""s; }

int main() { ::std::string const s(); ::std::cout << '>' << s << "<\n"s; }

::std::cout
>1<

In C++  wird diese Schreibweise aber als Deklaration einer Funktion  »s« interpretiert.

Immer, wenn ein Quelltext sowohl als Funktionsdeklaration als auch als Variablendeklaration interpretiert werden kann, hat die Interpretation als Funktionsdeklaration den Vorrang.

Es ist also nicht möglich, eine Fehlinitialisierung mit leeren runden Klammern zu schreiben.

Die richtige Schreibweise zur Fehlinitialisierung ist also nicht »::std::string const s();«, sondern »::std::string const s;«.

(Das folgende Zitat begründet, warum die Funktion wohl auch definiert  sein muß.)

Zitat *
Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required.

Die Adressen von Funktionen werden bei der verwendeten C++ -Implementation stets nur symbolisch als »1« ausgegeben (nach Wandlung in den Typ »bool«), was die oben zu sehende Ausgabe erklärt.

main.cpp

#include <iostream> /* ::std::cout */
#include <ostream> /* << */
#include <string> /* ::std::string */

using namespace ::std::literals;

::std::string s() { return ""s; }

int main()
{ ::std::string const s();
bool const b = s;
::std::cout << '>' << b << "<\n"s; }

::std::cout
>1<

Die Fehlinitialisierung mit geschweiften Klammern

Eine Fehlinitialisierung mit leeren Klammern ist aber möglich, wenn dabei geschweifte Klammern verwendet werden.

C++  garantiert, daß bei einer Initialisierung mit leeren geschweiften Klammern immer  der Fehlkonstruktor aktiviert wird.

main.cpp

#include <iostream> /* ::std::cout */
#include <ostream> /* << */
#include <string> /* ::std::string */

using namespace ::std::literals;

int main() { ::std::string const s{}; ::std::cout << '>' << s << "<\n"s; }

::std::cout
><

Die Tatsache, daß bei Verwendung geschweifter Klammern keine Verwechslung mit einer Funktionsdeklaration möglich ist, erklärt, warum oft empfohlen wird, die Schreibweise mit geschweiften Klammern falls möglich zu bevorzugen.

Die Fehlinitialisierung mit runden und  geschweiften Klammern

Falls ein Konstruktor, dessen Parameter eine Initialisierungsliste ist, mit einer leeren Initialisierungsliste aktiviert werden soll, so ist dafür die Schreibweise (bei einer Variablen »s«) nicht etwa die Schreibweise »s{}«, sondern die Schreibweise »s( {} )« zu verwenden.

Das folgende Programm verwendet nun also den Konstruktor, dessen Parameter den Typ »::std::initializer_list< char >« hat, seine Ausgabe unterscheidet sich aber nicht von dem vorigen Programm, das den Fehlkonstruktor aktivierte. Bei Verwendung anderer Klassen als der Klasse »::std::string« könnte es jedoch einen Unterschied geben.

main.cpp

#include <iostream> /* ::std::cout */
#include <ostream> /* << */
#include <string> /* ::std::string */

using namespace ::std::literals;

int main() { ::std::string const s( {} ); ::std::cout << '>' << s << "<\n"s; }

::std::cout
><

Die Fehlinitialisierung mit Gleichheitszeichen und  geschweiften Klammern

“main.cpp

#include <iostream> /* ::std::cout */
#include <ostream> /* << */
#include <string> /* ::std::string */

using namespace ::std::literals;

int main() { ::std::string const s = {}; ::std::cout << '>' << s << "<\n"s; }

::std::cout
><

Im voranstehenden Programm sehen wir die Kopier-Listen-Initialisierung  mit der Schreibweise »s = {}«.

(Die Schreibweise »s{}« wäre hingegen eine Direkt-Listen-Initialisierung .)

Bei dieser Kopier-Listen-Initialisierung mit leeren geschweiften Klammern wird ebenfalls ein Konstruktor aktiviert, dessen Parameterliste bei einer Funktion zu einem Aufruf mit leeren Klammern verträglich wäre.

Im Gegensatz zur Direkt-Listen-Initialisierung werden bei der Kopier-Listen-Initialisierung jedoch nur Konstruktoren herangezogen, die nicht  mit »explicit« gekennzeichnet sind.

Seiteninformationen und Impressum   |   Mitteilungsformular  |   "ram@zedat.fu-berlin.de" (ohne die Anführungszeichen) ist die Netzpostadresse von Stefan Ram.   |   Eine Verbindung zur Stefan-Ram-Startseite befindet sich oben auf dieser Seite hinter dem Text "Stefan Ram".)  |   Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram. Schlüsselwörter zu dieser Seite/relevant keywords describing this page: Stefan Ram Berlin slrprd slrprd stefanramberlin spellched stefanram722165 stefan_ram:722165 Fehlinitialisierung in C++ Stefan Ram, Berlin, and, or, near, uni, online, slrprd, slrprdqxx, slrprddoc, slrprd722165, slrprddef722165, PbclevtugFgrsnaEnz Erklärung, Beschreibung, Info, Information, Hinweis,

Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram.
https://www.purl.org/stefan_ram/pub/fehlinitialisierung_c++