6
#include<iostream>
struct A {
  A () {
    std::cout << "A::A()\n";
  }
};
A my_a;  // works fine and prints the above line

int main () {}

根据 C++ 标准,驻留在多个文件中的全局对象初始化的顺序是未指定的。
即在 1 个文件中定义的全局对象将按从上到下的顺序调用它们的构造函数。但是,如果有多个这样的文件,那么哪个文件将是第一个到最后一个,是实现定义的还是未指定的。

现在,std::cout两者my_a都是全局对象。这意味着上面的代码是一个UB,它是否正确(即初始化惨败)?
可能,编译器可能足够聪明,可以std在移动到其他对象之前先初始化对象。仍然为了清楚起见,是否有任何完整的证明方法可以为跨多个文件的全局对象执行日志记录?

4

1 回答 1

8

是的,没关系,而不是 UB。声明的流的使用iostream由标准明确定义。

27.4 标准 iostream 对象

2在第一次ios_base::Init构造类对象之前或期间,以及在任何情况下,在类的主体main开始执行之前的某个时间构造对象并建立关联。293 在程序执行期间对象不会被破坏。294包含<iostream> 在翻译单元中的结果应如同定义了具有静态存储<iostream>ios_base::Init 持续时间的实例一样。类似地,整个程序应该表现得好像至少有一个ios_base::Init 具有静态存储持续时间的实例。

因此标准要求cout在第一次创建之前初始化它ios_base::Init#include<iostream>保证它会在那里。因此,通过包含 iostream,您可以隐式定义ios_base::Init静态实例并保证 cout 将正常工作。

另请注意 294 明确指出静态对象的构造函数和析构函数被允许使用这些对象。

294) 静态对象的构造函数和析构函数可以访问这些对象以从标准输入读取输入或将输出写入标准输出或标准错误。

C++03 编辑:虽然之前给出的所有引号都是每个 C++11 和 C++03 没有“定义ios_base::Initiostream 包含”规则。C++03 仍然在 #260 而不是 294 下对静态对象的构造函数和析构函数有注释,因此对于 C++03 仍然允许在静态对象构造函数中使用 cout。

于 2013-04-26T08:33:23.143 回答