"Unbekannter Softwarefehler" bei globaler Variable einer Templateklasse mit statischem Member
-
Folgendes Beispiel
using namespace std; template<typename T> class foo { public: foo() { v.push_back(this); } static vector<foo<T>*> v; }; template<typename T> vector<foo<T>*> foo<T>::v; foo<int> f; int main() { }liefert mir (VS 2008) beim Starten den Fehler "Die Ausnahme "Unbekannter Softwarefehler" (0xc0000417) ist in der Anwendung an der Stelle 0x7858ccb5 aufgetreten.". Nach ein bisschen Debuggen fand ich heraus, dass das
push_backfehlschlägt, konkreter einreturn begin();im durchpush_backaufgerufeneminsert. Ich vermute deshalb, dassvzum Zeitpunkt des Konstruktoraufrufes noch nicht vollständig konstruiert ist.
Dieser Fehler tritt nur auf, wennfooeine Templateklasse ist undfeine globale Variable. Ich war aber bisher der Meinung, dass statische Member vor dem Konstruktor konstruiert sind.Deshalb meine Frage: gibt es für dieses Verhalten einen Grund (im Standard festgelegt), mache ich eventuell etwas falsch, oder ist hier gar ein Bug im VS (andere Compiler konnte ich leider nicht testen)?
-
Dein Code läuft zumindest bei mir unter Visual Studio 2010.
-
ipsec schrieb:
Deshalb meine Frage: gibt es für dieses Verhalten einen Grund (im Standard festgelegt)
Ja - d.h., das Verhalten ist potentiell undefiniert, weil die Reihenfolge der Instantiierung von f und foo<int>::v unspezifiziert ist.
Siehe auch Order of initialization in instantiation unitsObiger Code kann funktionieren, z.B. dann, wenn die Initialisierung von v statisch durchgeführt wird. Oder aber die Initilisierung passiert gerade zufällig in der gewünschten Reihenfolge.
Jedenfalls müsstest du, um das gewünschte Verhalten mit Sicherheit zu erreichen, foo<int>::v zuvor explizit instantiieren.
-
Vielen Dank, camper, das beantwortet schon mal einiges.

camper schrieb:
Jedenfalls müsstest du, um das gewünschte Verhalten mit Sicherheit zu erreichen, foo<int>::v zuvor explizit instantiieren.
Doofe Frage: wie mache ich das?
-
ipsec schrieb:
Vielen Dank, camper, das beantwortet schon mal einiges.

camper schrieb:
Jedenfalls müsstest du, um das gewünschte Verhalten mit Sicherheit zu erreichen, foo<int>::v zuvor explizit instantiieren.
Doofe Frage: wie mache ich das?
template vector<foo<int>*> foo<int>::v;
-
Eine Alternative wäre auch eine funktionslokale statische Variable, denn diese wird beim ersten Aufruf der Funktion initialisiert. Wenn die Funktion gar nie aufgerufen wird, fällt die Konstruktion von
vweg.template<typename T> class foo { public: foo() { GetV().push_back(this); } private: static vector<foo<T>*>& GetV() { static vector<foo<T>*> v; return v; } };
-
Vielen Dank euch beiden.
Die Variante mit der expliziten Instantiierung liefert bei mir leider den gleichen Fehler, aber Nexus' Idee gefällt mir sehr gut. Damit entfällt auch diese umständliche Syntax bei der Definition.