static method + static variable



  • Hallo,

    innerhalb einer statischen Methode versuche ich eine globale Variable zu setzen (Minimalbeispiel):

    class foo
    {
    public:
        static int i;
        static void meth()
        {
            i = 5;
        }
    };
    

    Leider gibt es hier einen Linker Error, aber wieso?



  • Weil die Definition von i fehlt:

    class foo
    {
    public:
        static int i;
        static void meth()
        {
            i = 5;
        }
    };
    // foo.cpp
    int foo::i = 0;
    


  • Warum wurde das eigentlich so festgelegt? Mal aus reinem Interesse.



  • Scorcher24 schrieb:

    Warum wurde das eigentlich so festgelegt? Mal aus reinem Interesse.

    Das "static int i" in der Klassendefinition ist nur die Deklaration einer Variablen. Es kann keine Definition sein, weil sonst in jeder Übersetzungseinheit, die den Header mit der Klassendefinition einbindet, ein eigenes foo::i definiert wäre und eine Änderung daran in Übersetzungseinheit A keinen Einfluss auf foo::i in Übersetzungseinheit B hätte.
    Wenn das aber alles nur Deklarationen sind, dann muss in irgendeiner Übersetzungseinheit explizit eine Definition erfolgen, damit der Compiler für die Variable auch den nötigen Speicher reserviert und der Linker weiß, wo dieses foo::i denn überhaupt liegt, auf das in ÜE A und ÜE B so munter zugegriffen wird.



  • Ja, aber man könnte dies doch durchaus automatisieren. Sprich, der Compiler legt die Variable selbstständig an. Dann hat man auch nicht diese hässlichen Definitionen am Anfang der Source Datei. Naja, nicht wichtig.



  • Scorcher24 schrieb:

    Ja, aber man könnte dies doch durchaus automatisieren. Sprich, der Compiler legt die Variable selbstständig an.

    Inkonsistenzen gibt es schon genügend in C++. Warum sollten sich statische Variablen in Klassen anders als globale verhalten?

    Andererseits wäre ein Modulsystem schon einmal praktisch – dann aber auch richtig.



  • Scorcher24 schrieb:

    Ja, aber man könnte dies doch durchaus automatisieren. Sprich, der Compiler legt die Variable selbstständig an. Dann hat man auch nicht diese hässlichen Definitionen am Anfang der Source Datei. Naja, nicht wichtig.

    Wann soll er sie anlegen und vor allem wie soll er sie initialisieren? Der Compiler kann sie nicht anlegen. Der wüsste nämlich beim Compilieren von ÜE B nicht, ob er in ÜE A schon die Variable angelegt hat oder nicht. Und wenn der Entwickler in ÜE C dann auch noch eine Initialisierung für die Variable definieren möchte, gehts völlig durcheinander. Das Anlegen der Vaiable könnte höchstens der Linker machen, wenn er merkt, dass es nirgendwo manuell gemacht wurde (durch Definition + Initialisierung). Der ist aber nur fürs Linken zuständig, nicht fürs Compilieren. Sprich, er kann den Code für die Initialisierung, der durchaus ein längerer Funktionsuafruf sein könnte, nicht erzeugen, weil beim Linken der Code bereits erzeugt sein muss.
    Die Notwendigkeit, die Variable manuell zu definieren, folgt also umittelbar aus dem Übersetzungsmodell von C++.



  • Naja, ist nur ne Kleinigkeit die mich stört.
    Genauso wie dass es Compiler nicht hinbekommen ints und floats auf 0 zu initialisieren und Pointer auch auf NULL.
    Die Initialisierungslisten mancher Klassen sind so überladen, nur weil ich eben eine korrekte initialisierung auf NULL benötige, damit die Abfrage

    if (ptr == NULL)
    

    auch wirklich funktioniert.



  • Das ist eine Mischung aus C-Kompatibilität und der "dont pay for what you dont use"-Mentalität von C++. Die eingebauten Typen mit 0 zu initialisieren braucht bestimmt einen oder zwei Clock-cycles, deshalb macht man das erst dann wenn und nur falls man es braucht.



  • Hauptsächlich C-Kompatibilität schätze ich.
    Für "don't pay for what you don't use" würde opt-out über ein Keyword reichen:

    class foo
    {
    private:
        int noinit m_bar;
    };
    
    // Oder alternativ in der Initializer-List:
    
    foo::foo() :
        m_bar(undefined)
    {
    }
    


  • hustbaer schrieb:

    Hauptsächlich C-Kompatibilität schätze ich.
    Für "don't pay for what you don't use" würde opt-out über ein Keyword reichen:

    class foo
    {
    private:
        int noinit m_bar;
    };
    
    // Oder alternativ in der Initializer-List:
    
    foo::foo() :
        m_bar(undefined)
    {
    }
    

    Dann lassen wir's lieber so, wie es ist.



  • hustbaer schrieb:

    Hauptsächlich C-Kompatibilität schätze ich.
    Für "don't pay for what you don't use" würde opt-out über ein Keyword reichen

    Das hieße, du müsstest es explizit angeben, dass du es NICHT haben willst. Das ist ja genau nicht der "don't pay" Ansatz. Der sagt "wenn du etwas haben willst, musst du es explizit angeben, sonst kriegst du das billigste", sprich, der billigste Teil ohne Schnickschnack ist der Default-Fall.


Anmelden zum Antworten