是否保证std :: cout被初始化?

Inb*_*ong 40 c++ constructor global-variables

我对C++的了解是不应该假设全局实例的构造(和析构)的顺序.

当我用编译器std::cout和析构函数中使用的全局实例编写代码时,我遇到了一个问题.

std::cout也是iostream的全局实例.是否std::cout保证在任何其他全局实例之前进行初始化?

我写了一个简单的测试代码,它工作得很好,但我仍然不知道为什么.

#include <iostream>

struct test
{
    test() { std::cout << "test::ctor" << std::endl; }
    ~test() { std::cout << "test::dtor" << std::endl; }
};

test t;

int main()
{
    std::cout << "Hello world" << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

它打印

test::ctor
Hello world
test::dtor
Run Code Online (Sandbox Code Playgroud)

代码是否有可能无法按预期运行?

GMa*_*ckG 43

答案取决于您使用的是C++ 03还是C++ 11.

在C++ 11中,您的代码保证可以正常工作,但在C++ 03中,它是未指定的; 您唯一的保证是,在main()输入时,标准流已初始化.(也就是说,所有主流实现在运行任何动态初始化之前都会初始化它们,使它们可以正常使用.)

您可以通过构造std::ios_base::Init对象来强制初始化,如下所示:

#include <iostream>

struct test
{
    test() { std::cout << "test::ctor" << std::endl; }
    ~test() { std::cout << "test::dtor" << std::endl; }

private:
    std::ios_base::Init mInitializer;
};

test t;

int main()
{
    std::cout << "Hello world" << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

现在,当test构造时,它初始化mInitializer并保证流已准备好使用.

C++ 11修复了这种有点烦人的行为,就好像每个实例#include <iostream>都跟着一样static std::ios_base::Init __unspecified_name__;.这可以自动保证流可以使用.

  • 在C++ 03中,明显的意图(如脚注所示)是为了保证std :: cin/std :: cout对象在其他对象之前完全构造. (2认同)

Gui*_*e07 11

根据§27.3/ 2:

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

  • @BasileStarynkevitch:排序为true,但脚注265(引自§27.3/ 2)说它应该有效:"静态对象的构造函数和析构函数可以访问这些对象以从stdin读取输入或将输出写入stdout或stderr." 这可能不是规范性的,但至少清楚地表明他的代码应该起作用的*intent*. (11认同)
  • @BasileStarynkevitch:确实如此.该段落继续说:"在翻译单元中包含<iostream>的结果应该好像<iostream>定义了具有静态存储持续时间的ios_base :: Init实例." 并且由于同一翻译单元中的静态非局部变量按声明顺序初始化,因此保证在您的其他非本地静态之前初始化`cout`.(假设你在声明你的变量之前你#include <iostream>`,我真诚地希望) (3认同)
  • 相对于其他静态对象而言,std :: cout的构造顺序没有说明。 (2认同)
  • @MatthieuM。我同意,但这也不是我的意思。该标准确实没有指定何时初始化`cout`。它仅指定对于特定的翻译单元,结果就好像在该标头中定义了一个实例一样。这只是保证即使在静态对象中也可以安全使用`cout`的标准方法。 (2认同)