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-used(3.2, 3.7.1)。 此外,尝试使用__attribute__ ((init_priority(int)))或__attribute__ ((constructor))对模板成员的初始化产生了警告:attributes after parenthesized initializer ignored,并且我不知道其他关于静态初始化的技巧。感谢提供答案的任何人!
odr-use
规则的意图是覆盖可能具有文件作用域对象的动态共享对象(DSO)。如果通过dlopen()
在main函数启动后引入DSO,则显然无法初始化DSO中的所有内容,但理论上dlopen()
可以确保在调用DSO中的任何其他内容之前初始化DSO中的所有内容。我想最终的答案取决于您编译的操作系统/架构的ABI定义。 - Joe Z