2009-04-23 18 views
11

ich ein statisches Klassenmitglied haben, die einige Behälter ist, wieBestücken ein statisches Element Container in C++

(foo.h)

class Foo 
{ 
    ... 
private: 
    static list<string> s_List; 
} 

Ich brauche die Liste mit einer Reihe von aufzufüllen spezifische Werte. Eigentlich sollte es auch const sein, aber das könnte das Problem weiter verschlimmern. Alle Klassenmemberfunktionen sind statisch, daher ist es nicht sinnvoll, sie in einem Konstruktor zu initialisieren.

Antwort

15

eine gemeinsame Lösung ist so etwas wie dies zu tun:

// header 
class Foo 
{ 
... 
private: 
    static list<string> s_List; 
} 

// cpp 
list<string> init() 
{ 
    list<string> tmp; 
    ... fill tmp with strings 

    return tmp; 
} 

list<string> Foo::s_List(init()); 

die andere Methode ist wie Neil Butter vorgeschlagen.

+1

Ich denke, Ihre ist eine vielseitige Lösung, weil ein privates Mitglied ohne viel Aufwand initialisiert werden kann ... und ist es möglich, dass s_List const ist? Dann sollte init() auch die Konstantenliste zurückgeben. Recht? – Maleev

+0

Auch aus der Sicht der Leistung: wäre es nicht besser, einen Verweis auf tmp zurückzugeben, weil es sowieso durch den impliziten Kopierkonstruktor (oder Zuweisungsoperator, korrigiert mich) in der letzten Zeile kopiert wird? Dann wird es nicht zweimal geschehen. Irgendwelche Unterlieferungen, die ich nicht gezählt habe? – Maleev

+0

ja, Sie könnten es in eine Konst-Liste <> ändern. Sie können jedoch keine Referenz zurückgeben, da "tmp" eine lokale Variable ist und nach dem Verlassen von init() abstirbt. –

0

Die Wege, die ich (der Autor der Frage) vergeblich versucht habe, dies zu tun.


Ich habe versucht, smth wie (in foo.cpp) zu tun:

list<string> Foo::s_List = list<string>(); 
Foo::s_List.insert("apple"); 
Foo::s_List.insert("bannana"); 
Foo::s_List.insert("grapes"); 

Aber das gibt einen Compiler-Fehler.


Dann dachte ich an eine Initialize() -Methode zu machen und sie direkt aus dem Code

void Foo::Initialize() 
{ 
    s_List.insert("rats"); 
    s_List.insert("cats"); 
} 

Foo::Initialize(); 

// Fehler Aufruf: Compiler hält es für ein redefenition des Verfahrens, kein Anruf.


Der einzig gangbare Idee links (havent versuchte noch) wäre zu prüfen, ob die Liste in jeder Methode leer ist, die es verwendet, und wenn es der Fall ist, rufen Initialisieren(). Aber das ist hässlich!

+0

Initialisieren sollte eine statische Funktion sein. Sorry für die Frage, aber versuchen Sie, Funktionsaufrufe * außerhalb * Funktionen oder Methoden zu tun? – Emiliano

+0

Ja, in der Tat war ich :) – Maleev

0

Eine mögliche Lösung wäre die Verwendung einer Zugriffsmethode, die überprüft, ob sie initialisiert ist, und wenn dies nicht der Fall ist.

8

Eine weitere Alternative ist es, eine einfache initialiser Klasse zu erstellen:

list <string> Foo::s_List; 

struct Init { 
    Init() { 
     Foo::s_List.insert("apple"); 
     Foo::s_List.insert("bannana"); 
     Foo::s_List.insert("grapes"); 
    } 
}; 

static Init doInit; 

Beachten Sie, dass, wie die Liste privat ist, wird dies benötigen Sie wahrscheinlich Init einen Freund von Foo zu machen. Es ist auch oft praktisch, solche Klassen durch die Klasse, die sie initialisieren, zu enthalten.

Aber ich lese gerade Ihre Frage erneut und ein anderer Gedanke tritt auf - wenn die Liste const ist, werden Sie vermutlich nicht ändern, in welchem ​​Fall ein einfaches Array von Strings, initialisiert mit den Strings in sortierter Reihenfolge sein kann eine bessere Lösung. Es ist sicherlich schneller zu suchen (mit std :: binary_search) als eine Liste und kann natürlich leicht initialisiert werden.

+0

+1, Beat mich dazu :) –

+2

Gute Idee. Es funktioniert garantiert, da statische Member und globale Variablen in der Reihenfolge in jeder Quelldatei initialisiert werden. Da die Liste in der ursprünglichen Frage privat ist, wird eine Freundschaftsdeklaration benötigt. –

+0

Sieht gut aus. Danke – Maleev

1

Es hängt davon ab, welche Werte Sie in diese Liste eingeben müssen. Sind sie statisch oder benötigen sie eine Form der Berechnung?

Wenn sie statisch sind, können Sie dies tun:

namespace { 
    const char* const initVals[] = { "A", "B", "C" }; 
} 

list<string> Foo::s_list(initVals, initVals + 3); 
4

Wenn Ihr Compiler C++ 0x unterstützt, das ist eigentlich trivial zu erreichen.

#include <iostream> 
#include <list> 

class Foo 
{ 
public: 
    static std::list<std::string> s_List; 
}; 

std::list<std::string> Foo::s_List = {"hello", "world", "asdf", "qwerty"}; 

int main() 
{ 
    for(const std::string& str : Foo::s_List) 
     std::cout << str << std::endl; 

    return 0; 
} 

Dies funktioniert für const und nicht-const statische Mitglieder. Ich habe dieses Snippet mit clang-4.2, gcc-4.7, gcc-4.6 und gcc-4.5 getestet. Gcc-4.5 unterstützt nicht die aktualisierte für Syntax, so dass Sie eine traditionelle für Schleife mit Iteratoren verwenden müssen. Vergessen Sie auch nicht, das Flag -std = C++ 0x an den Compiler zu übergeben. Ich bin einigermaßen zuversichtlich, dass Visual Studio dies ebenfalls unterstützt, aber ich weiß es nicht genau und weiß nicht welche Versionen.

Verwandte Themen