对于 gcc (4.8) 或 icc (14.0) 是否有任何模式或其他非标准机制可以保证静态局部变量的早期安全构造?
我需要一个本地静态对象引用的全局集合,以便在运行时进行可控制的粗略分析。标准的延迟构造(以及处理锁定或冗余的 thread_local 集合)对我造成了极大的伤害,并且在开始时拥有完整的点列表将是非常有利的。
有希望实现这一目标吗?
#include <iostream>
#include <deque>
// Really want to build this list before main() started!
struct ProfilePoint;
static std::deque<ProfilePoint *> pps;
// Costly construction, but only ever with literal/constexpr params.
// Templating, etc., also discourages non-local building in reality.
struct ProfilePoint {
ProfilePoint(int id, char const *i) : id_(id), inf_(i) { pps.push_back(this); }
void doStuff() { /* ... */ }
int id_;
char const *const inf_;
};
// Functions like this will be called concurrently in reality.
void bar(int cnt) {
for (int i = 0; i < cnt; ++i) {
// Dropping in a local definition/call should be enough to hook in to system
static ProfilePoint pp(2, "description in a string literal");
pp.doStuff();
/* ... */
}
}
void dump() {
std::cout << "[";
for (ProfilePoint *pp: pps) { std::cout << " " << pp->id_ << ":" << pp->inf_; }
std::cout << " ]" << std::endl;
}
int main() { dump(); bar(5); dump(); } // "[ ]" then "[ 2 ]" in gcc/icc
我已经阅读了 C++11 规范的 Schwarz Counters 和第 3.6.2 (basic.start.init) / 6.7 (stmt.decl) 部分,但我对编译器特定的行为和找不到其他人发布有关尝试实现此技巧的信息。
接受的答案:
正如约翰在下面指出的那样,所有类(可能)在 main() 之前初始化其静态成员,但鉴于此C++11 §9.4.2/5 [class.static.data]
并§9.8/4 [class.local]
禁止本地类中的静态数据成员,该类在本地类上模板化并具有该类的静态数据成员可以在 start-time 完成其初始化。相当绝妙的洞察力,甚至比我最初想象的还要微妙!
// John Bandela's solutions (slightly condensed):
template <class TPPDesc> struct PPWrapper_T { static ProfilePoint p; };
template <class TPPDesc>
ProfilePoint PPWrapper_T<TPPDesc>::p(TPPDesc::id(), TPPDesc::desc());
#define PROFILE_POINT(ID, DESC, NAME) \
struct ppdef_##NAME { \
static int id() { return ID; } \
static char const *desc() { return DESC; } \
}; \
static PPWrapper_T<ppdef_##NAME> NAME // semicolon must follow!
// ...
void foo() {
PROFILE_POINT(2, "another_description", pp);
pp.p.doStuff();
}
另请注意,对集合使用 Meyers 单例方法完成了此方法的整体安全性。但是,可能必须锁定集合以防止点的并发静态初始化。我仍然需要检查规范以确认此规范以及静态成员初始化是否实际上强制在 main() 之前完成。