Statische Datenelementinitialisierung

Warum muss die Initialisierung statischer Datenelemente außerhalb der class erfolgen?

class X { public: int normalValue = 5; //NSDMI static int i; }; int X::i = 0; 

Warum ist das statische Datenelement (hier “i”) nur eine Deklaration, keine Definition?

   

Es ist wichtig, den Initialisierer, der angibt, was sein Anfangswert ist, und die Definition zu unterscheiden . Dieser geänderte Code ist gültig mit dem Initialisierer in der classndefinition:

 class X { public: int normalValue = 5; static const int i = 0; // declaration, with initializer }; const int X::i; // definition 

Dh Was außerhalb der class sein muss, ist eine Definition, nicht die Initialisierung.

Dies liegt daran, dass eine Variable eine Adresse im Speicher haben muss (es sei denn, sie wird nur in begrenzten Situationen verwendet, z. B. in konstanten Konstantenexpress für die Kompilierung.)

Eine nicht statische Elementvariable existiert innerhalb des Objekts, zu dem sie gehört, so dass ihre Adresse von der Adresse des Objekts abhängt, in dem sie enthalten ist. Jedes Mal, wenn Sie ein neues X erstellen, erstellen Sie auch eine neue X::normalValue Variable. Die Lebensdauer des nicht statischen Datenelements beginnt mit dem Konstruktor der class. Die NSDMI-Syntax hat nichts mit der Adresse der Variablen im Speicher zu tun, sondern ermöglicht es Ihnen, einen Anfangswert an einer Stelle anzugeben, anstatt ihn in jedem Konstruktor mit einer expliziten Konstruktorinitialisierungsliste zu wiederholen.

Auf der anderen Seite ist eine statische Elementvariable nicht in einer Instanz der class enthalten, sie existiert unabhängig von irgendeiner einzelnen Instanz und existiert vom Start des Programms an einer festen Adresse. Damit eine statische Membervariable (oder ein anderes globales Objekt) eine eindeutige Adresse erhält, muss der Linker genau eine Definition der statischen Variablen in genau einer Objektdatei anzeigen und ihr eine Adresse zuweisen.

Da eine statische Variable genau eine Definition in genau einer Objektdatei benötigt, ist es nicht sinnvoll, diese Definition in der class bereitzustellen, da classndefinitionen normalerweise in Headerdateien vorhanden sind und in mehreren Objektdateien enthalten sind. Obwohl Sie in der class einen Initialisierer bereitstellen können, müssen Sie das statische Datenelement dennoch irgendwo definieren.

Sie können es auch wie eine extern Variable deklarieren:

 namespace X { extern int i; } 

Dies deklariert die Variable, aber irgendwo im Programm muss eine Definition sein:

 int X::i = 0; 

Sie müssen eine separate Definition für ein statisches Datenelement angeben (wenn es odr-verwendet wird , wie in C ++ 11 definiert), weil diese Definition sich irgendwo befinden soll – in einer und nur einer Übersetzungseinheit. Statische classndatenelemente sind grundsätzlich globale Objekte (globale Variablen), die im classnbereich deklariert sind. Der Compiler möchte, dass Sie eine bestimmte Übersetzungseinheit auswählen, die den tatsächlichen “Körper” jedes globalen Objekts enthält. Sie müssen entscheiden, in welcher Übersetzungseinheit das eigentliche Objekt platziert werden soll.

Das classnelement “static” ist wie eine global zugewiesene Variable (es bezieht sich nicht auf die einzelne classninstanz). Daher muss es in einer Objektdatei (und in der Datei “.cpp” deklariert) als Symbol wie jedes andere enthalten sein Globale Variable.

Ein einfacher classnmember (nicht statisch) befindet sich in dem Speicherblock, der für die classninstanz reserviert ist.

Der einfache Grund ist, weil classn normalerweise in Headerdateien deklariert sind, die oft in mehreren cpp-Dateien enthalten sind. Statische Datenelemente haben eine externe Verknüpfung und müssen in genau einer Übersetzungseinheit deklariert werden, wodurch sie nicht in einer class definiert werden können.

Wie Juanchopanza darauf hinweist, ist folgendes erlaubt:

 struct A { const static int i = 1; }; 

Dies ist jedoch nur eine Deklaration, keine Definition. Sie müssen es immer noch definieren, wenn Sie meine Adresse irgendwo benutzen wollen. Beispielsweise:

 f(int); g(int&); X x; // Okay without definition for template arguments char a[A::i]; // Okay without definition, just using value as constant expression &A::i; // Need a definition because I'm taking the address f(A::i); // Okay without definition for pass by value g(A::i); // Need a definition with pass by reference 

Beachten Sie, dass es möglich ist, das statische Datenelement am Deklarationspunkt zu initialisieren, wenn es vom const-Integraltyp des Const-Aufzählungstyps ist:

Aus dem C ++ 03-Standard, §9.4.2

Wenn ein statisches Datenelement vom Const-Integral- oder Const-Aufzählungstyp ist, kann seine Deklaration in der classndefinition einen Konstanteninitialisierer angeben, der ein ganzzahliger Konstantenausdruck sein soll (5.19).

 struct Foo { static const int j = 42; // OK }; 

Wenn der Compiler Binärcode aus einer Einheit generiert (extreme Vereinfachung: eine cpp-Datei und alle darin enthaltenen Header), wird ein Symbol für die statische Variable und schließlich den Initialisierungscode für diese Variable ausgegeben.

Es ist in Ordnung, wenn ein statisches Variablensymbol in mehreren Einheiten deklariert wird, aber es ist nicht in Ordnung, es mehrfach zu initialisieren.

Sie müssen also sicherstellen, dass der Initialisierungscode nur für eine einzelne Einheit ausgegeben wird. Dies bedeutet, dass die statische Variable in genau einer Einheit definiert sein muss.

Statische Daten Mitglied

 #include #include class static_var { static int count; //static member of class public : void incr_staticvar() { count++; } void outputc() { cout< <"Value of Static variable Count :- "<