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

22 浏览
0 Comments

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

在C++中,不能假设全局实例的构造和析构顺序。\n当我在编写一个使用std::cout在构造函数和析构函数中的全局实例的代码时,我有一个问题。\nstd::cout也是iostream的一个全局实例。是否保证在其他全局实例之前初始化std::cout?\n我写了一个简单的测试代码,它完美地工作了,但是我仍然不知道为什么。\n

#include 
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;
}

\n它会打印出:\n

test::ctor
Hello world
test::dtor

\n是否有可能代码运行不如预期?

0
0 Comments

Is std::cout guaranteed to be initialized?

关于静态对象构造顺序的问题,你的问题是关于std::cout是否保证被初始化的顺序。我相信语言规范没有明确定义这个顺序。GCC提供了init_priority属性来控制初始化顺序。但实际上,我相信你不必太担心这个问题。

0
0 Comments

《C++标准库》中的§27.3/2规定了关于std::cin、std::cout等对象的构造和关联建立的时间,即在类ios_base::Init的对象被构造之前或者在其构造期间,并且在main函数体开始执行之前。然而,这并没有说明std::cout相对于其他静态对象的构造顺序。

虽然如此,脚注265(从§27.3/2引用)表示应该能够正常工作:“静态对象的构造函数和析构函数可以访问这些对象,从stdin读取输入或者向stdout或stderr输出。”虽然这可能不是规范性的说明,但至少明确了代码应该可以正常工作的意图。

实际上确实如此。段落继续说明:“在一个翻译单元中包含的结果应该是,它定义了一个具有静态存储期的ios_base::Init的实例。”由于同一翻译单元中的静态非局部变量以声明的顺序初始化,std::cout在其他非局部静态变量之前已经被初始化了。(假设在声明变量之前使用了#include ,我真诚地希望如此)

那么,如果在#include 之前包含了其他头文件,这些头文件声明了静态变量会怎么样呢?

如果它们使用了std::cout,那么它们必须自己包含#include

你忘记了独立编译模型,仅仅因为一个头文件创建了一个静态/全局变量,并不意味着该变量的构造函数被内联在头文件中!它可以被放在一个cpp文件中(该cpp文件包含了#include ),在这种情况下,头文件本身并不需要包含#include

我同意,但这也不是我的重点。标准确实没有指定std::cout何时被初始化。它只是规定了对于特定的翻译单元,结果应该是“好像”在该头文件中定义了一个实例。这只是一种用于保证即使在静态对象中也可以安全使用std::cout的标准方式。

0
0 Comments

在C++03和C++11中,关于std::cout是否保证初始化的答案是不同的。在C++11中,你的代码被保证可以工作,但在C++03中是未指定的;你唯一的保证是在进入main()函数之前,标准流已经被初始化。(也就是说,所有主流的实现在运行任何动态初始化之前都会初始化它们,使它们可以正常使用。)

你可以通过构造一个std::ios_base::Init对象来强制初始化,代码如下:

#include 
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 之后都跟着static std::ios_base::Init __unspecified_name__;来修复了这种略微烦人的行为。这自动保证了流可以使用。

在C++03中,明显的意图(如脚注所示)是保证std::cin/std::cout对象在其他对象之前完全构造出来。

0