C ++ - 非本地静态对象与本地静态对象

时间:2017-02-22 08:32:25

标签: c++

关于Scot Meyers的书“Effective C ++”和第4项:非本地静态对象在使用之前可以是未初始化的(静态在这种情况下意味着“全局”,具有静态生命)。如果用一个本地 - static对象替换它,该对象是在一个返回对它的引用的函数内创建的,那么该对象在使用前肯定会被初始化。

我总是有一个带常量的文件。我在.hpp文件中声明extern const int a;并在.cpp文件中定义它。但那么同样的事情会发生吗? a可以是未初始化的。或不?同样的规则是否适用于内置类型?

2 个答案:

答案 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对象是在控制流第一次到达声明时构造的。