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

mar*_*trz 5 c++ static static-order-fiasco c++11

根据C++ 11规范:

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

这意味着如果我的代码看起来像这样:

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

// 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;
}
Run Code Online (Sandbox Code Playgroud)

那么我应该安全地打电话,cerr不存在静态初始化惨败的风险.

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

Bo *_*son 7

该段的完整引用包括:

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

并附上脚注

293)如果他们可以这样做,则鼓励实现早于需要初始化对象.

因此,保证是iostream 最迟在进入main时工作.除非翻译单位包括,否则没有严格要求他们应该提前工作<iostream>.

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

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

  • 是的,它应该.但这是一个奇怪的解决方法. (2认同)