gpt4 book ai didi

c++ - gcc 中模板的非延迟静态成员初始化?

转载 作者:可可西里 更新时间:2023-11-01 16:19:21 24 4
gpt4 key购买 nike

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]:)

It is implementation-defined whether the dynamic initialization of a non-local variable with static storage duration is done before the first statement of main. If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first odr-use (3.2) of any function or variable defined in the same translation unit as the variable to be initialized.

... A non-local variable with static storage duration having initialization with side-effects must be initialized even if it is not odr-used (3.2, 3.7.1).

另外,尝试 __attribute__ ((init_priority(int)))__attribute__ ((constructor))模板成员的初始化产生了 warning: attributes after parenthesized initializer ignored ,而且我不知道有关静态初始化的其他技巧。

在此先感谢任何可以给我答案的人!

最佳答案

标准保证在从外部源使用与您的对象相同的翻译单元中的任何函数/变量之前初始化静态存储持续时间对象。

此处的措辞旨在与共享库一起使用。因为共享库可以在 main() 启动后动态加载,语言规范必须足够灵活以应对它。但只要您从翻译单元外部访问您的对象,那么您就可以保证它会在您被授予访问权限之前构建(除非您正在做一些病态的事情)。

但是如果它在同一编译单元中的另一个静态存储持续时间对象的构造函数中使用,这不会阻止它在初始化之前被使用。

但您可以通过以下技术轻松地手动提供静态对象在使用前正确初始化的保证。

只需将静态变量更改为静态函数即可。然后在函数内部声明一个返回的静态成员。所以您可以像以前一样使用它(只需添加 ())。

template <class T>
struct PWrap_T
{
static P& p_s(); // change static variable to static member function.
// Rather than the type being P make it a reference to P
// because the object will be held internally to the function
};

template <class T>
P& PWrap_T<T>::p_s()
{
// Notice the member is static.
// This means it will live longer than the function.
// Also it will be initialized on first use.
// and destructed when other static storage duration objects are destroyed.
static P p_s_item(T::id(), T::desc());

return p_s_item;

// Note its not guaranteed to be created before main().
// But it is guaranteed to be created before first use.
}

所以在这里您可以获得全局的好处(无论它们是什么)。您得到保证的构造/破坏,并且您知道对象在使用之前将被正确构造。

您唯一需要做的改变是:

void bar(int cnt) {
for (int i = 0; i < cnt; ++i) {
PP(2, "description", pp);
pp.p_s().doStuff();
// ^^ Add the braces here.
}
}

关于c++ - gcc 中模板的非延迟静态成员初始化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20601358/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com