Hat gcc irgendwelche Garantien bezüglich der Startzeit von statischen Elementen, insbesondere in Bezug auf Vorlagenklassen?Nicht verzögerte statische Elementinitialisierung für Vorlagen in gcc?
Ich möchte wissen, ob ich eine harte Garantie bekommen kann, dass statische Mitglieder (PWrap_T<T>::p_s
) vor main()
initialisiert werden, wenn Klassen über mehrere Kompilierungseinheiten instanziiert werden. Es ist nicht praktisch zu versuchen, ein Symbol von jeder Kompilierungseinheit am Anfang von main manuell zu berühren, aber es ist mir nicht klar, dass irgendetwas anderes funktionieren würde.
Ich habe mit Methoden wie bar()
in verschiedenen Einheiten getestet und immer das gewünschte Ergebnis bekommen, aber ich muß wissen, wann/ob jemals gcc den Teppich ausreißen und ob es vermeidbar.
Werden außerdem alle statischen Member von einem DSO initialisiert, bevor eine Bibliothek geladen wird?
#include <iostream>
#include <deque>
struct P;
inline std::deque<P *> &ps() { static std::deque<P *> d; return d; }
void dump();
struct P {
P(int id, char const *i) : id_(id), inf_(i) { ps().push_back(this); }
void doStuff() { std::cout << id_ << " (" << inf_ << ")" << std::endl; }
int const id_;
char const *const inf_;
};
template <class T>
struct PWrap_T { static P p_s; };
// *** Can I guarantee this is done before main()? ***
template <class T>
P PWrap_T<T>::p_s(T::id(), T::desc());
#define PP(ID, DESC, NAME) /* semicolon must follow! */ \
struct ppdef_##NAME { \
constexpr static int id() { return ID; } \
constexpr static char const *desc() { return DESC; } \
}; \
PWrap_T<ppdef_##NAME> const NAME
// In a compilation unit apart from the template/macro header.
void dump() {
std::cout << "[";
for (P *pp : ps()) { std::cout << " " << pp->id_ << ":" << pp->inf_; }
std::cout << " ]" << std::endl;
}
// In some compilation unit.
void bar(int cnt) {
for (int i = 0; i < cnt; ++i) {
PP(2, "description", pp);
pp.p_s.doStuff();
}
}
int main() {
dump();
PP(3, "another", pp2);
bar(5);
pp2.p_s.doStuff();
}
(C++ 11 §3.6.2/4 - [basic.start.init] :)
Es wird die Implementierung definiert, ob die dynamische Initialisierung eines nicht-lokalen Variable mit statischer Speicherdauer wird vor der ersten Anweisung von main ausgeführt. Wenn die Initialisierung auf einen Zeitpunkt nach der ersten Anweisung von main verschoben wird, soll sie vor der ersten odr-Verwendung (3.2) einer Funktion oder Variablen erfolgen, die in der gleichen Übersetzungseinheit wie die zu initialisierende Variable definiert ist.
... Eine nicht lokale Variable mit statischer Speicherdauer mit Initialisierung mit Nebeneffekten muss initialisiert werden, auch wenn sie nicht odr-used ist (3.2, 3.7.1).
Auch versuchen __attribute__ ((init_priority(int)))
oder __attribute__ ((constructor))
für die Initialisierung der Vorlage Mitglieds ergab warning: attributes after parenthesized initializer ignored
, und ich kenne keine anderen Tricks in Bezug auf statische Initialisierung.
Vielen Dank im Voraus an jeden, der mir eine Antwort darauf geben kann!
Ich stelle mir die 'odr-use' Regel dynamische gemeinsame Objekte decken soll (DSOs), die möglicherweise Datei-scope-Objekte haben. Sie können natürlich nicht alles in einem DSO initialisieren, wenn es nach dem Start von 'dlopen()' eingefügt wird, aber theoretisch kann 'dlopen()' sicherstellen, dass alles im DSO initialisiert wird, bevor Sie etwas anderes im DSO aufrufen. Ich kann mir vorstellen, dass die Antwort letztlich von der ABI für jedes Betriebssystem/jede Architektur definiert wird, für die Sie sich zusammensetzen. –
Das Singleton-Muster löst das Problem, oder? – lkanab