静态顺序初始化fiasco,iostream和C ++ 11

时间:2016-10-20 16:34:34

标签: c++ c++11 static static-order-fiasco

根据C ++ 11规范:

  

在翻译单元中包含<iostream>的结果应该好像<iostream>定义了具有静态存储持续时间的ios_base::Init实例。同样,整个程序的行为应该至少如此   具有静态存储持续时间的ios_base::Init的一个实例

这意味着如果我的代码如下:

// A.cpp
#include <iostream>
using namespace std;
unsigned long foo() {
    cerr << "bar"; 
    return 42;
}

// B.cpp

using namespace std;
extern unsigned long foo();

namespace {
unsigned long test() {
    int id = foo();
    return id;
}

unsigned long id = test();
}


int main() {
     return 0;
}

然后我应该安全地调用cerr而不存在静态初始化惨败的风险。

不幸的是,代码段错误...为什么?我不认为gcc 6.2.1决定忽略C ++ 11规范,我在A.cpp中包含了<iostream>。根据规范,它应该足够了。

1 个答案:

答案 0 :(得分:6)

该段的完整引用包括:

  

构造对象并在第一次之前或期间的某个时间建立关联   时间构造类ios_base :: Init的对象,并且无论如何在main主体开始之前   执行。 293)

并附上脚注

  

293)如果他们可以这样做,则鼓励实现早于所需的时间初始化对象。

因此,保证在输入main时iostream最晚将工作。除非翻译单元包含<iostream>,否则没有严格要求他们应该提前工作。

你找到了绕过这个的方法!

从B.cpp调用foo()时,A.cpp中包含的ios_base::Init实例可能已经初始化,也可能没有。