Statische Member in C++ definieren

Lesezeit: 9 Minuten

Ich versuche, eine öffentliche statische Variable wie folgt zu definieren:

public :
         static int j=0;        //or any other value too

Ich erhalte einen Kompilierungsfehler in genau dieser Zeile: ISO C++ verbietet die In-Class-Initialisierung des nicht konstanten statischen Members „j“.

  1. Warum ist es in C++ nicht erlaubt?

  2. Warum dürfen const-Member initialisiert werden?

  3. Bedeutet dies, dass statische Variablen in C++ nicht wie in C mit 0 initialisiert werden?

Vielen Dank !

  • Verwenden Sie statisches Inline

    – Lewis Kelsey

    1. April 2021 um 23:48 Uhr


Benutzer-Avatar
Eugen Constantin Dinca

(1.) Warum ist es in C++ nicht erlaubt?

Aus Häufig gestellte Fragen zu Stil und Technik von Bjarne Stroustrup in C++:

Eine Klasse wird typischerweise in einer Header-Datei deklariert und eine Header-Datei ist typischerweise in vielen Übersetzungseinheiten enthalten. Um jedoch komplizierte Linkerregeln zu vermeiden, erfordert C++, dass jedes Objekt eine eindeutige Definition hat. Diese Regel würde gebrochen werden, wenn C++ die klasseninterne Definition von Entitäten erlauben würde, die als Objekte im Speicher gespeichert werden müssten.

(2.) Warum dürfen const-Elemente initialisiert werden?

[dirkgently said it better]

(3.) Bedeutet das, dass statische Variablen in C++ nicht wie in C mit 0 initialisiert werden?

Soweit ich weiß, wird, solange Sie das statische Mitglied var in einer .cpp-Datei deklarieren, es mit Null initialisiert, wenn Sie nichts anderes angeben:

// in some .cpp
int Test::j; // j = int();

  • Danke für die tolle Antwort, du hast mich daran gehindert, mir das Herz aus dem Kopf zu reißen! Ich habe jedoch eine Frage: Gibt es eine Möglichkeit, beim Definieren von Referenzelementen einen Nullzeiger anzugeben?

    – Tim Visée

    20. Februar 2014 um 22:59 Uhr


  • @TimVisee Ich bin mir nicht sicher, ob es möglich ist – zumindest auf tragbare Weise ohne UB -, aber Sie würden am Ende eine ungültige Referenz erhalten. Wenn Sie NULL-Semantik wünschen, verwenden Sie einfach einen Zeiger oder verwenden Sie möglicherweise etwas wie Boost Optional.

    – Eugen Constantin Dinca

    22. Februar 2014 um 4:39 Uhr

Benutzer-Avatar
Dennis Müller

Sie müssen die statische Variable in einer .cpp-Datei und nicht in der Klassendeklaration initialisieren.

Wenn Sie eine statische Variable in der Klasse deklarieren, kann sie verwendet werden, ohne eine Klasse zu instanziieren.

//Header file
class Test
{
  public:
    static int j;
};

//In cpp file

//Initialize static variables here.
int Test::j = 0;

//Constructor
Test::Test(void)
{
   //Class initialize code
}

Warum ist es in C++ nicht erlaubt?

Solange Sie es nicht definieren, wird die Variable nicht zu einem L-Wert.

Warum dürfen const-Member initialisiert werden?

Auch in diesem Fall ist eine Definition erforderlich, wenn Sie die Adresse der Variablen übernehmen wollen.

9.4.2 Statische Datenelemente

2 Die Deklaration eines statischen Datenmembers in seiner Klassendefinition ist keine Definition und kann einen anderen unvollständigen Typ als cv-qualified void haben. Die Definition für ein statisches Datenelement muss in einem Namensraumbereich erscheinen, der die Klassendefinition des Elements einschließt. In der Definition im Geltungsbereich des Namensraums muss der Name des statischen Datenelements durch seinen Klassennamen unter Verwendung des Operators :: qualifiziert werden. Der Initialisierungsausdruck in der Definition eines statischen Datenmembers liegt im Bereich seiner Klasse

Außerdem ist dies in erster Linie ein Nutzungsartefakt, sodass Sie Folgendes schreiben können:

class S {
      static const int size = 42;
      float array[ size ];
};

Bedeutet dies, dass statische Variablen in C++ nicht wie in C mit 0 initialisiert werden?

Nein, sie sind:

3.6.2 Initialisierung von nicht lokalen Variablen

Variablen mit statischer Speicherdauer (3.7.1) oder Thread-Speicherdauer (3.7.2) müssen mit Null initialisiert werden (8.5), bevor irgendeine andere Initialisierung stattfindet.

Allerdings werden die Dinge in C++0x etwas kniffliger. Alle Literaltypen können jetzt initialisiert werden (im Gegensatz zu nur ganzzahligen Typen im aktuellen Standard), was bedeuten würde, dass alle skalaren Typen (einschließlich Floats) und einige Klassentypen jetzt mit einem Initialisierer in der Deklaration initialisiert werden können.

  • Warum ist keine Definition für eine statische konstante Ganzzahl erforderlich, wenn die Adresse nicht verwendet wird? Es (static-const-int definiert in .h) kompiliert, verknüpft erfolgreich ohne Definition. Wenn ja, seit wann erlaubt C++ diese Art der Deklaration ohne Definition, seit C++98 ? seit C++03 ? Bitte authentische Quellen. C++ Standard (9.4.2) ist nicht synchron mit den Compilern. Es erwähnt, dass das Mitglied noch definiert werden muss, wenn es im Programm verwendet wird. Ich werde Ihnen also sagen, dass ich nicht nach Zitaten aus dem C++-Standard suche. Was gut sein wird, ist GCC Changelog/C++ Committee Notes.

    – sm Raj

    20. September 2014 um 15:50 Uhr

Benutzer-Avatar
tc.

Die kurze Antwort:

Es ist gleichbedeutend mit sagen extern int Test_j = 0;.

Wenn es kompilieren würde, was würde passieren? Jede Quelldatei, die includes Die Header-Datei Ihrer Klasse würde ein Symbol namens Test::j definieren, das mit 0 initialisiert wird. Dem Linker gefällt das normalerweise nicht.

Benutzer-Avatar
Muhammad Rehan

class GetData        
{    
private:     
static int integer;   //Static variable must be defined with the extension of keyword static;      
public:      
static void enter(int x)      
{       
integer = x;  //static variable passed through the static function    
}
static int  show()   //declared and defined
{
    return integer;   //will return the integer's value
}        
};        
int GetData::integer = 0;    //Definition of the static variable       
int main()      
{      
   GetData::enter(234);    //value has been passed through the static function enter. Note that class containing static variables may not have the object in main. They can be called by scope resolution operator in main.
   cout<<GetData::show();      
}     

Die Frage ist eher, warum muss man explizit a machen static Mitglied, das innerhalb der Klasse definiert ist const oder inlinewenn Sie das nicht für a tun müssen static Methode, die automatisch erstellt wird inline wenn innerhalb der Klasse definiert. Allgemeiner gesagt lautet die Frage, warum es das Definieren einer Methode in einer Klasse schafft inline und warum kann das Definieren eines statischen Members in einer Klasse nicht auch so behandelt werden inline oder wie ein globales Symbol für einen Dateibereichsklassenbereich wie eine Out-of-Line-Definition, anstatt es zu einem Compilerfehler zu machen.

Wenn Sie es definieren static constwird es die Last optimieren und wenn Sie es zwingen, den Wert zu laden, indem Sie es machen volatile const Wenn Sie die Adresse davon nehmen, erhalten Sie einen Linker-Fehler, da das Symbol niemals ausgegeben wird (clang zwingt Sie, a static volatile const aus der Reihe, aber gcc nicht). Dies ist viel anders als a const im Dateibereich.

Was mir das sagt ist, dass die Voreinstellung für a static Mitglied ist es, überhaupt kein Symbol zu emittieren, anstatt zu sein inline. const ermöglicht es, den Wert direkt in den Code zu optimieren (weshalb Sie ihn tatsächlich als definieren können const, denn wenn Sie dies nicht getan hätten, würden Sie kein Symbol und dann Verweise auf dieses fehlende Symbol haben), aber der Compiler gibt immer noch kein Symbol aus. Aber warum ist das so? Warum nicht einfach machen inline standardmäßig wie eine Methode, anstatt überhaupt kein Symbol auszugeben?

Der einzige Unterschied zu einer Methode besteht darin, dass dieselbe Definition mehrere unterschiedliche Werte haben kann. Wenn Sie den Klassentyp in einem anonymen Namespace definieren, hätte er eine statische (lokale) Verknüpfung, und Sie könnten die Neudefinitionsfehler vermeiden. Nun hätte es mehrere unterschiedliche Zustände in den verschiedenen Übersetzungseinheiten, wenn es in die Übersetzungseinheiten aufgenommen würde, eine Methode jedoch nicht (es hätte mehrere Definitionen, aber diese Definitionen wären identisch). Dasselbe gilt für die nichtstatische Verknüpfung, bei der eine der Definitionen willkürlich ausgewählt wird, wenn dies der Fall ist inline, andernfalls gibt es einen Mehrfachdefinitionsfehler. Mit static Verknüpfung, es hindert Sie auch immer noch daran, a zu definieren static Mitglied in der Klasse ohne inlineweil es immer noch kein Symbol emittieren würde.

Weil es Sie daran hindert, ein Mitglied zu definieren (dh kein Symbol auszugeben), wenn es (statische Verknüpfung) und nicht (externe Verknüpfung, daher Linkerfehler) mehrere Wertzustände haben würde und wenn es einen Linkerfehler geben würde (externe Verknüpfung ) und wenn es keinen Linker-Fehler (statische Verknüpfung) geben würde, kann es nicht mit diesen Eigenschaften zu tun haben.

Sie müssen sich also fragen, warum die Absicht eines in einer Klasse definierten Members out-of-line (dh wie ein reguläres Symbol für den Gültigkeitsbereich einer Datei) und die Absicht einer in einer Klasse definierten Methode sein sollte inline (dh Symbol nur ausgeben, wenn es in der Übersetzungseinheit verwendet wird, und nur ein Symbol in der comdat-Gruppe auswählen, das verwendet werden soll). Ich meine, wenn ein Programmierer eine statische Methode in einer Klasse definiert, wird davon ausgegangen, dass es dieselbe Methode ist, aber wenn er ein Mitglied definiert, kann es viele verschiedene Werte haben, was ein Problem für die Comdat-Verknüpfung ist, weil Sie es nicht wissen welches Symbol es auswählen wird, und wird ein stiller Logikfehler sein:

// file.cpp
#include <iostream>

struct c {
    static inline int k = 3;
};

int func(){
    std::cout << c::k;
    return 0;
}
// main.cpp
#include <iostream>

struct c {
    static inline int k = 4;
};

int main() {
    std::cout << c::k; // prints 3
}

Wenn es Sie dazu zwingt, es außerhalb der Reihe zu definieren, erhalten Sie stattdessen einen Linker-Neudefinitionsfehler, der die Diagnose erleichtert. Zugegebenermaßen würde das gleiche Problem auftreten, wenn die Methodendefinitionen unterschiedlich wären, und die ganze Annahme hier ist, dass sich die Klassendefinition in einer Header-Datei befinden soll – also warum sollte die Definition jemals anders sein.

Wenn sich die statische Elementdefinition in der Klasse wie eine Out-of-Line-Definition verhalten würde, würde dies zu Linkerfehlern führen, wenn Sie sie in mehrere Dateien einfügen, sodass sie aufgrund des Ärgers standardmäßig nicht als Out-of-Line interpretiert wird. Ich sehe jedoch keinen Grund, warum es nicht implizit gemacht wird inline wie eine in der Klasse definierte statische Methode ist.

Ich glaube nicht, dass es eine andere Antwort gibt als „so ist es“. Es ist ein bisschen wie, warum Sie nicht verwenden können static um einer Methode eine statische Verknüpfung zu geben (und es ist ein Fehler, oder die static wird komplett ignoriert -fpermissive), aber Sie können es in einen anonymen Namespace einschließen, um dies zu erreichen (und der anonyme Namespace muss die Definition und die Deklaration (also die Klasse) umgeben, nicht nur die Definition (oder nicht nur die Deklaration – aber das ist sowieso unmöglich, weil if Die Deklaration befindet sich in einem anonymen Namensraum, dann muss die Definition enthalten sein oder sie wird nicht kompiliert)). Ich habe noch keine solche Antwort auf SO gesehen.

1013530cookie-checkStatische Member in C++ definieren

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy