我遇到了一些静态初始化顺序混乱的问题。我有一个类,在我的程序进入主程序之前不应该实例化/构造它。这是因为当程序进入主程序时,所有的静态初始化都已经完成了。显然,一个简单的答案就是不要将该类型的对象实例化/构造/初始化为静态变量,但我想进行检查,以防它意外发生并且有一个我无法发现的错误。
我考虑过设置一个标志 bHasEnteredMain,将其设置为 main 中的第一项,但这没有用,因为没有初始化顺序,因此该标志在该内存中具有与 true 等同的垃圾,所以它毫无用处。有办法吗?C++ 标准或编译器中是否有内置标志或类似的东西可以用作检查?
8
最佳答案
2
您可以拥有一个设置为的全局布尔值,然后在主函数中将false
其更改为。true
在许多平台上,全局简单对象在 C++ 运行时开始初始化非简单对象之前就已初始化。
另一个解决方案是使用 meyers 单例等价于计数器,在 main 开始时以及在不想静态构造的类的构造函数中调用它。
int count()
{
static int counter = 0;
counter++;
return counter;
}
如果返回除 1 之外的任何数字,main
那么它是在静态初始化期间调用的,并且存在该类的静态实例!
9
-
现在当对象位于另一个 TU 中时会发生什么?
– -
@NathanOliver 没关系,C++ 运行时尚未启动,它们在将应用程序或共享对象加载到内存中时由动态链接器初始化。
–
-
@NathanOliver 这可能与本例无关,因为这个全局变量专门供特定类使用,因此应在同一个 TU 中声明。它不是您打算在许多不同库中使用的通用标志。
– -
1@Barmar 静态初始化顺序混乱的重点在于多个 TU 中的静态对象没有定义顺序。这难道不意味着涉及多个 TU 吗?如果这一切都在一个 TU 中,那么一开始就没有问题,因为每个 TU 都有保证的总顺序。
–
-
@NathanOliver 然后我怀疑 OP 对未定义的静态初始化顺序感到困惑,并且认为它在 TU 中适用。
–
|
最好使用内部带有静态标志的函数(Meyers 的类似单例的构造)。根据需要,您可以这样做,例如:
#include <iostream>
//yes, the interface is somewhat clunky
bool mainWasCalled(bool mark = false)
{
static bool wasCalled{};
if (!wasCalled && mark) {
wasCalled = true;
}
return wasCalled;
}
struct S
{
S() { std::cout << mainWasCalled() << '\n'; }
};
static S staticS;
S globalS;
int main()
{
mainWasCalled(true);
S localS;
}
计数器递增main
也可以工作,选择你喜欢的接口。这基于以下原则:函数内的静态对象可防止静态初始化顺序失败——它在进入函数时被初始化。函数本身有效地操纵(并返回)全局变量的状态。
唯一的问题可能是当您的全局对象尝试从多个线程中调用此函数时;您可能会main()
在调用此函数之前与其他一些线程之间产生数据争用。
|
–
–
–
–
main
。–
|