关于Scot Meyers的书“Effective C ++”和第4项:非本地静态对象在使用之前可以是未初始化的(静态在这种情况下意味着“全局”,具有静态生命)。如果用一个本地 - static
对象替换它,该对象是在一个返回对它的引用的函数内创建的,那么该对象在使用前肯定会被初始化。
我总是有一个带常量的文件。我在.hpp文件中声明extern const int a;
并在.cpp文件中定义它。但那么同样的事情会发生吗? a
可以是未初始化的。或不?同样的规则是否适用于内置类型?
答案 0 :(得分:2)
尽管你可以,但是返回对" local-static"的引用并不是一个好主意。变量。该变量(推测)是在本地声明的,以将其范围缩小到封闭函数,因此试图以这种方式增加其范围是相当hacky。您可以将其设为全局变量并使用std::call_once之类的内容来保证在首次使用时初始化一次。返回对本地静态对象的可变引用也会引发线程安全问题,因为该函数可能不再可重入。
具有静态存储持续时间的POD类型保证为零初始化。您还可以使用常量表达式初始化它们,语言将保证在进行任何动态初始化之前初始化它们。这里a similar question可以提供一些额外的见解。
答案 1 :(得分:0)
有关静态初始化的问题称为static initialization order fiasco:
简而言之,假设你有两个静态对象x和y 单独的源文件,比如x.cpp和y.cpp。进一步假设 y对象的初始化(通常是y对象的构造函数) 在x对象上调用一些方法。
因此,如果您有另一个使用常量的翻译单元,那么您的程序很可能无法运行。有时它是文件链接在一起的顺序,有些平台甚至在doc中定义它(我认为Solaris就是这里的一个例子)。
The problem also applies to builtin types such as int. 常见问题解答中的示例是:
#include <iostream>
int f(); // forward declaration
int g(); // forward declaration
int x = f();
int y = g();
int f()
{
std::cout << "using 'y' (which is " << y << ")\n";
return 3*y + 7;
}
int g()
{
std::cout << "initializing 'y'\n";
return 5;
}
int main() {
std::cout << x << std::endl << y << std::endl;
return 0;
}
如果运行此示例,则输出为:
使用&#39; y&#39; (这是0) 初始化&#39; y&#39;
因此,首先进行零初始化,然后进行常量初始化(?)。
解决方案是 Construct On First Use Idiom:
构造首次使用成语的基本思想是包装你的 函数内的静态对象。
静态loca对象是在控制流第一次到达声明时构造的。