2012-01-09 80 views
33

我对C++的了解是,不应该假定全局实例的构造(和破坏)的顺序。std :: cout保证被初始化?

虽然我用全局实例编写代码,但在构造函数&析构函数中使用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; 
} 

它打印

test::ctor 
Hello world 
test::dtor 

是否有可能按预期的代码不能运行?

+1

关联 http://stackoverflow.com/questions/6919593/is-cout-guaranteed-available-during-static-deinitialization这也包括在答案的建设。 – adl 2012-01-09 07:11:12

+0

无法假定静态存储持续时间对象在全局作用域的初始化顺序,但有强制初始化顺序的技巧。 – 2012-01-09 10:04:28

+0

PS。还要注意破坏的顺序是有保证的(与构造相反)。 – 2012-01-09 10:11:59

回答

36

答案因使用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; 
} 

test它初始化mInitializer并保证流可以使用。

C++ 11通过充当#include <iostream>的每个实例后跟static std::ios_base::Init __unspecified_name__;来解决这个稍微令人讨厌的行为。这自动保证了流可以使用。

+2

在C++ 03中,明显的意图(如脚注所示)是为了确保std :: cin/std :: cout对象在其他对象之前完全构造。 – 2012-01-09 10:08:08

10

根据§27.3/ 2

目的[给std :: cin,标准::法院等]构造,并且 关联是在一些前或时间建立在第一个 时间内,构造了类ios_base :: Init的对象,并且在主体的主体开始执行之前,在任何情况下均为 。

+1

对于其他静态对象相对于std :: cout构造的顺序没有任何说明。 – 2012-01-09 07:06:16

+10

@BasileStarynkevitch:真正的排序,但脚注265(从第27.3/2节引用)表示它应该工作:“静态对象的构造函数和析构函数可以访问这些对象以从stdin读取输入或将输出写入标准输出或标准错误。这可能不是规范性的,但至少明确说明他的代码应该工作的意图。 – 2012-01-09 07:09:30

+3

@BasileStarynkevitch:它确实如此。该段继续说道:“在翻译单元中包含的结果应该如同定义了具有静态存储持续时间的ios_base :: Init的实例。”由于同一翻译单元中的静态非局部变量按照声明的顺序进行初始化,所以'cout'保证在其他非局部静态变量之前被初始化。 (假设你在#include '之前声明你的变量,我真心希望) – knatten 2013-05-12 16:30:06

2

你的问题是关于构造静态对象的顺序。我相信语言规范使其不确定。

GCC有init_priority属性可以与订单一起玩。

我相信你不应该在实践中担心太多。