Nichtinitialisierung in C++
Initialisierer
Als Initialisierer in der Deklaration einer Variablen bezeichnet man den auf den Variablennamen folgenden Teil. Wir zeigen im folgenden einige Beispiele von Deklarationen. Die genaue Bedeutung dieser Deklarationen wird erst später erklärt werden, aber wir können hier schon kennzeichnen, was der Initialisierer ist.
main.cpp
#include <iostream> /* ::std::cout */
#include <ostream> /* << */int main()
{ /* Initialisierer */
{ int const a {}; ::std::cout << a << '\n'; }
{ int const a = 1; ::std::cout << a << '\n'; }
{ int const a ( 2 ); ::std::cout << a << '\n'; }
{ int const a { 3 }; ::std::cout << a << '\n'; }
{ int const a ={ 4 }; ::std::cout << a << '\n'; }}::std::cout
0
1
2
3
4
Initialisierung
Als Objekt bezeichnet man in C++ einen Teil des Speichers, welcher den Wert einer Variablen eines bestimmte Typs aufnehmen (speichern) kann. Eine Variable ist ein Name für ein Objekt. Wenn man von einer „Variablen“ spricht meint man oft das von der Variablen benannte Objekt zusammen mit seinem Namen.
Wenn eine Variable angelegt (neu erzeugt) wird, dann wird ein Objekt des Typs der Variablen angelegt (Objekterzeugung) und jenes Objekt der Variablen wird dann oft auch initialisiert. Dies bedeutet, daß das Objekt der Variablen auf einen bestimmten Anfangszustand (Anfangswert) gesetzt wird. Diesen Vorgang nennt man Initialisierung.
Der Initialisierer einer Deklaration kann verwendet werden, um festzulegen, wie ein Objekt genau initialisiert werden soll.
Objekterzeugung
Wie im vorigen Abschnitt schon gesagt, wird beim Anlegen einer Variablen ein Objekt des Typs der Variablen erzeugt. Der Name der Variablen steht dann für dieses Objekt. Wir halten also fest, daß in C++ die gängige Vorgehensweise zum Erzeugen eines Objekts darin besteht, eine Variable des Typs des gewünschten Objekts zu definieren.
Nichtinitialisierung von Variablen fundamentaler Typen
Das folgende Beispiel zeigt eine Definition eines Objekts ohne Verwendung eines Initialisierers.
main.cpp
#include <iostream> /* ::std::cout */
#include <ostream> /* << */int main(){ int a; ::std::cout << a << '\n'; }
In einem Block deklarierte Variablen haben automatische Lebensdauer. Das heißt, daß das Objekt der Variablen bis zum Ende der Ausführung des Blocks existiert.
Im obigen Programm wird ein Objekt ohne Initialisierer definiert. Dies bedeutet bei den Typen »int«, »double«, »bool«, und »char«, daß keine Initialisierung vorgenommen wird: Wenn das zugehörige Objekt mit automatischer Lebensdauer nicht initialisiert wird, dann hat es einen unbestimmten Wert.
In dem obigen Programm wird der Wert des Objekts dann ausgeben. Dazu ist es nötig, den Wert des Objekts auszulesen. Bei einem Objekt mit unbestimmten Wert hat dies undefiniertes Verhalten. Dies bedeutet praktisch, daß solch ein Programm fehlerhaft ist. Solch ein Fehler wird jedoch nicht immer schon bei der Übersetzung eines Programms gemeldet. Er ist auch durch einfache Ausführung des Programms nicht ohne weiteres erkennbar.
Relevante Zitate maßgeblicher Quellen *
“If no initializer is specified for an object, the object is default-initialized «, N3797, 8.5p12s1
(If an object does not have class or array type ) “To default-initialize an object of type T means: ” (…) „no initialization is performed “, N3797, 8.5p7
“if no initialization is performed, an object with automatic or dynamic storage duration has indeterminate value.”, N3797, 8.5p12
“if the object to which the glvalue refers contains an indeterminate value, the behavior is undefined ”, N3797, 4.1p2
Konstanten
Bei Verwendung von »const« oder »constexpr« kann der Fehler, welcher im Fehlen einer Initialisierung besteht, schon beim Übersetzen diagnostiziert werden, da Konstanten initialisiert werden müssen.
main.cpp
#include <iostream> /* ::std::cout */
#include <ostream> /* << */int main(){ int const a; ::std::cout << a << '\n'; }
main.cpp
#include <iostream> /* ::std::cout */
#include <ostream> /* << */int main(){ constexpr int a; ::std::cout << a << '\n'; }
Relevante Zitate maßgeblicher Quellen
“A constexpr specifier used in an object declaration declares the object as const. Such an object shall have literal type and shall be initialized.”, N3797, 7.1.5p9s1
“If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.”, N3797, 8.5p7s2
Stil
Es wird empfohlen, Variablen stets ausdrücklich zu initialisieren. Die hier beschriebene Nichtinitialisierung sollte also vermieden werden. Wir werden später noch Möglichkeiten dazu behandeln.
Übungsfragen
? Verhalten eines Programms
main.cpp
#include <iostream> /* ::std::cout */
#include <ostream> /* << */int main(){ int a; ::std::cout << a << '\n'; }
Welche der folgenden Aussagen treffen bei jeder Ausführung des obenstehenden Programms unter einer C++ -Implementation immer zu?
- Anton Das obenstehende Programm gibt 0 aus.
- Berta Das obenstehende Programm gibt eine nicht näher bestimmte Zahl aus.
- Cäsar Das Verhalten des obenstehenden Programms ist nicht definiert.