Statische Member vs statische Variablen im anonymen Namespace



  • Hallo zusammen,

    in extrem seltenen Fällen braucht/verwendet man statische Variablen. Ich hab die letzten Tage darüber nachgedacht. 2 sinnvolle Varianten sind mir eingefallen. 1x eine statisches Member einer Klasse und 1x eine statische Variable die sich in einem anonymen namespace in cpp befindet. Meine Frage ist welche Variante besser wäre?

    Um ein Beispiel zu nennen verwende ich extrem selten statische Maps in Klassen. Der Inhalt dieser Map(s) sind pro Instanz unabhängig und werden durch eine Init Funktion im Konstruktor der Klasse initialisiert, sofern sie zu diesem Zeitpunkt leer ist. Wenn es unser Compiler erlauben würde, dann würde ich es in einen anonymen Namespace als const Map packen und sofort initialisieren/befüllen. Leider habe ich bis jetzt keine bessere Möglichkeit gefunden und bei jedem Objekt diese Map komplett von 0 zu erstellen und zu befüllen finde ich ineffizient. Ein switch und case wäre für solche Fälle dann auch unübersichtlich.



  • Als statisches Member muss die Variable in der Klassendefinition stehen, also üblicherweise im Header-File. Das hat sowohl Vor- als auch Nachteile. Ein Vorteil ist dass man so schneller sieht dass es diese statische Variable gibt. Ein Nachteil davon ist dass der Typ bekannt sein muss, zumindest als forward-declaration.

    Bzw. man könnte argumentieren dass es logisch passender und "reiner" ist, eine Sache die nur für Klasse X nötig ist, auch als Member von Klasse X zu implementieren. Allerdings ist das IMO kein sehr starkes Argument, denn Operatoren werden auch gern als freie Funktionen (evtl. als friend) umgesetzt.

    Ist also alles sehr subjektiv.

    Ich denke beides ist OK.
    Persönlich würde ich vermutlich eher ein statisches Member machen. Ausnahme: wenn der Typ nicht forward-declared werden kann, und die Header die den Typ definiert nicht super billig zu inkludieren ist.

    Um ein Beispiel zu nennen verwende ich extrem selten statische Maps in Klassen. Der Inhalt dieser Map(s) sind pro Instanz unabhängig und werden durch eine Init Funktion im Konstruktor der Klasse initialisiert, sofern sie zu diesem Zeitpunkt leer ist.

    Eine Alternative dazu wäre Meyers' Singleton:

    std::map<int, int> const& myStaticMap() {
        static auto const m = []() {
            // init code
        }();
        return m;
    }
    
    

    Damit ist das ganze ab C++11 automatisch thread-safe.



  • @hustbaer sagte in Statische Member vs statische Variablen im anonymen Namespace:

    Als statisches Member muss die Variable in der Klassendefinition stehen, also üblicherweise im Header-File. Das hat sowohl Vor- als auch Nachteile. Ein Vorteil ist dass man so schneller sieht dass es diese statische Variable gibt. Ein Nachteil davon ist dass der Typ bekannt sein muss, zumindest als forward-declaration.

    Man kann statische Member forward deklarieren? Daran habe ich gar nicht gedacht.

    @hustbaer sagte in Statische Member vs statische Variablen im anonymen Namespace:

    Damit ist das ganze ab C++11 automatisch thread-safe.

    Leider haben wir keinen C++11 Compiler bzw. nur einen Teil der neuen Features von 11.

    @hustbaer sagte in Statische Member vs statische Variablen im anonymen Namespace:

    Persönlich würde ich vermutlich eher ein statisches Member machen

    Mein Gedanken zu einer statischen Variable in einem anonymen Namespace war, dass es dadurch rein im cpp bleibt und die Schnittstelle sich nach außen hin nicht verändert.



  • @KK27 sagte in Statische Member vs statische Variablen im anonymen Namespace:

    Persönlich würde ich vermutlich eher ein statisches Member machen

    Mein Gedanken zu einer statischen Variable in einem anonymen Namespace war, dass es dadurch rein im cpp bleibt und die Schnittstelle sich nach außen hin nicht verändert.

    Ja, so kann man es auch sehen. Hab ja geschrieben: ist alles sehr subjektiv.



  • @hustbaer sagte in Statische Member vs statische Variablen im anonymen Namespace:

    Bzw. man könnte argumentieren dass es logisch passender und "reiner" ist, eine Sache die nur für Klasse X nötig ist, auch als Member von Klasse X zu implementieren. Allerdings ist das IMO kein sehr starkes Argument, denn Operatoren werden auch gern als freie Funktionen (evtl. als friend) umgesetzt.

    Ich würde da argumentieren, dass bei Operatoren, wo man das macht, ohnehin nicht immer eindeutig bestimmt ist, zu welcher Klasse der nun gehören soll. Gehört operator+(T, U) zu T, dem von rechts ein U addiert wird, oder zu U, bei dem das T von links addiert wird?

    Ich denke aber der eigentliche Grund für freie Funktionen ist hier, dass man bei einem Member-operator+ auf der linken Seite auch tatsächlich den konkreten Typen benötigt, während man mit einer freien Funktion auch X und Y addieren kann, falls diese implizit in T und U konvertierbar sind. Auch kann man die eng verwandten symmetrischen Operatoren (T + U und U + T) als freie Funktionen schön direkt untereinander in der selben Datei implementieren, falls man für jede Klasse eine eigene .cpp-Datei hat (Übersichtlichkeit).

    Ansonsten meine (subjektive) Meinung zur eigentlichen Frage: Wenn die Variablen logisch eindeutig zu der Klasse gehören, dann bevorzuge ich statische Member. Ich habe alles was zusammen gehört immer gerne möglichst kompakt in einem "Paket", die Klasse und alle "Globalen" auf denen sie eventuell arbeitet. Wenn ich beim refaktorisieren die Klasse irgendwann in eine andere Quellcodedatei verschiebe, will ich nicht die zugehörige Globale vergessen und mich dann irgendwann wundern, wofür die überhaupt da war, wenn sie allein zurückgeblieben ist 😁



  • Danke für die Antworten.

    @Finnegan sagte in Statische Member vs statische Variablen im anonymen Namespace:

    Ansonsten meine (subjektive) Meinung zur eigentlichen Frage: Wenn die Variablen logisch eindeutig zu der Klasse gehören, dann bevorzuge ich statische Member. Ich habe alles was zusammen gehört immer gerne möglichst kompakt in einem "Paket", die Klasse und alle "Globalen" auf denen sie eventuell arbeitet. Wenn ich beim refaktorisieren die Klasse irgendwann in eine andere Quellcodedatei verschiebe, will ich nicht die zugehörige Globale vergessen und mich dann irgendwann wundern, wofür die überhaupt da war, wenn sie allein zurückgeblieben ist

    So mache ich das meistens auch. Wenn etwas definitiv zur Klasse gehört dann als Member(funktion). Andernfalls als freie Konstante/Funktion im Cpp, sofern sich dafür eine eigene Klasse (noch nicht) lohnt.


Anmelden zum Antworten