Liebe Leserinnen, liebe Leser,

in diesem Beitrag teile ich eine interessante Beobachtung, die ich vor Kurzem über statische Klassenvariablen, falls sie mit auto benutzt werden, gemacht habe. Stellen wir den folgenden Code, den ein Grünschnabel oder eine müde Person am Abend ohne Zögern schreiben könnte, unter die Lupe:

C++

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
 * ducks.h
 */

class QuackCounter {
public:
    // class machinery

    static auto getQuacks() {return numberOfQuacks;}

private:
    static auto numberOfQuacks;
}

Das ist ein allgemeiner Fehler. Eine nicht initialisierte Variable, über die während der Kompilierzeit die folgende Fehlermeldung erstellt: error: declaration of ‘auto numberOfQuacks’ has no initializer (diese Meldung ist ohne das static Stichwort auch zu erwarten). Das passiert, weil der Compiler für die Bestimmung des Typs ein Wert sofort braucht, also es ist leicht einzusehen, warum dieses Merkmal von auto zu der Popularität stark beigetragen hat: während der Kompilierzeit bekommt man eine Fehlermeldung für nicht initialisierte Variablen. Dieses Problem ist durch die unmittelbare Initialisierung der Variable einfach behoben. Eine müde/ungeübte Person würde vielleicht die flogende Sache bedenkenlos machen:

C++

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
 * ducks.h
 */

class QuackCounter {
public:
    // class machinery
    
    static auto getQuacks() {return numberOfQuacks;}

private:
    static auto numberOfQuacks = 0;
}

Leider ist das nicht, was der Compiler braucht, und es wird mal wieder mit der folgenden Fehlermeldung widersprechen: error: ISO C++ forbids in-class initialization of non-const static member. Hmmm. Was könnte man machen? Die Lösung ist ganz einfach:

C++

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
 * ducks.h
 */

class QuackCounter {
public:
    // class machinery
    
    static auto getQuacks() {return numberOfQuacks;}

private:
    static int numberOfQuacks;  // declare it here
}

.

C++

1
2
3
4
5
/*
 * ducks.cpp
 */
    
int QuackCounter::numberOfQuacks = 0;  // and define it in the .cpp file

Die erste Änderung war die Entfernung von auto vor der Variable, aber mittlerweile wurde die Funktion nicht geändert: sie hat auto noch weiter. Diese Situation ist eine gute Gelegenheit das zu verstehen, dass auto und static nicht einander ausschließend sind, sondern stammen die Inkopatibiltäten aus den sehr festen Initialisationsregeln, die auto selbst erfordert.

Die zweite Änderung war der Umzug der Definition der Variable zu einer .cpp Datei. Warum bracuht dann die Definition in einer .cpp Datei zu sein? Ein schneller Nachschlag in stackoverflow.com ergab mir die richtige Antworten. Die folgende Sachen sind herforgehoben:

  • Statische Klassenvariablen haben externe Verbindung, und sie müssen in genau einer Übersetzungeinheit angegeben werden. Es ermöglicht eine Definition drinnen der Klassen nicht (von Jesse Good)
  • Um eine Einzeladdresse für eine statische Klassenvariable (oder andere globalen Objekte) zu erwerben, muss der Linker nur genau eine einzige Definition der statischen Variable nur in genau einer einzigen Datei sehen (von Jonathan Wakely)

Also, die Lektion ist schon gelernt:

  1. auto und static sind nicht einander ausschließend, sondern brauchen sie einen entsprechenden Partner, mit dem sie koppeln können
  2. statische Variablen können nur in einer einzigen .cpp Datei definiert werden, und deswegen erlauben sie auto nicht