gcc是否對靜態成員初始化時間有任何保證,特別是關於模板類?gcc中模板的非延遲靜態成員初始化?
我想知道我是否能夠很好地保證靜態成員(PWrap_T<T>::p_s
)將在main()
之前初始化,當時類在多個編譯單元中實例化。在main的開始處嘗試手動觸摸每個編譯單元中的符號是不現實的,但我不清楚其他任何方法都可行。
我已經喜歡在不同的單位bar()
和總是得到期望的結果的方法測試,但我需要知道當/如果曾經GCC將抽出地毯出來,無論是可以預防的。
此外,在庫加載完成之前,DSO中的所有靜態成員都會被初始化嗎?
#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] :)
它實現定義是否一個非本地的動態初始化具有靜態存儲持續時間的變量在main的第一條語句之前完成。 如果初始化被推遲到main的第一條語句之後的某個時間點,它應該在第一個odr-use(3.2)之前出現,在任何函數或變量中定義在同一個翻譯單元中作爲要初始化的變量。
...具有初始化帶副作用的靜態存儲持續時間的非局部變量必須初始化,即使它沒有使用odr(3.2,3.7.1)。
此外,試圖__attribute__ ((init_priority(int)))
或__attribute__ ((constructor))
爲模板成員的初始化產生warning: attributes after parenthesized initializer ignored
,我知道關於靜態初始化沒有其他招數。
在此先感謝任何能夠給我答案的人!
我想象中的'ODR-use'規則意在包括可能有文件範圍的對象的動態共享對象(的DSO)。如果DSO在主啓動後被帶入'dlopen()',那麼顯然不能初始化DSO中的所有內容,但理論上'dlopen()'可以在調用DSO中的其他任何內容之前確保DSO中的所有內容都已初始化。我想最終的答案是由ABI爲您編譯的任何操作系統/體系結構定義的。 –
單身模式解決了這個問題,不是嗎? – lkanab