C++ iostream必须包含哪些文件?

C++ iostream必须包含哪些文件?,c++,c++11,C++,C++11,我正在写一个快速示例来演示全局对象的初始化/销毁。在这样做的过程中,我遇到了以下难题 一般来说,您不应该在头文件中包含头文件中的代码不需要的任何头文件。这有助于减少混乱和编译时间 在我的示例中,我从类定义中分离出构造函数和析构函数的定义。在我的例子中,它们非常琐碎,我可能只是将它们内联,但这只是一个例子 实际定义构造函数和析构函数的转换单元包括iostream,以便可以向控制台输出调用 我的问题是当我们开始讨论在全局范围内声明类的实例时。现在我运行到初始化顺序和转换单元。翻译单元中全局变量的初始

我正在写一个快速示例来演示全局对象的初始化/销毁。在这样做的过程中,我遇到了以下难题

一般来说,您不应该在头文件中包含头文件中的代码不需要的任何头文件。这有助于减少混乱和编译时间

在我的示例中,我从类定义中分离出构造函数和析构函数的定义。在我的例子中,它们非常琐碎,我可能只是将它们内联,但这只是一个例子

实际定义构造函数和析构函数的转换单元包括
iostream
,以便可以向控制台输出调用

我的问题是当我们开始讨论在全局范围内声明类的实例时。现在我运行到初始化顺序和转换单元。翻译单元中全局变量的初始化顺序定义良好。全局变量从一个转换单元到另一个转换单元的初始化顺序不太明确。在我的示例中,它可以执行以下操作之一:

  • 初始化第一个源文件,然后初始化第二个源文件
  • 初始化第二个源文件,然后初始化第一个源文件
  • 初始化第二个源文件
24.4.1/2: 对象[std::cout在我的例子中]是在类
ios_base::Init
的对象第一次构造之前或期间的某个时间构造的,并且在任何情况下都是在主体开始执行之前。这些对象在程序执行期间不会被销毁。在翻译单元中包含
的结果应如同
定义了具有静态存储持续时间的
ios_base::Init
实例一样。类似地,整个程序的行为应类似于至少有一个具有静态存储持续时间的
ios_base::Init
实例

请注意,此段落调用了“如同”规则,因此它不必创建
ios_base::Init的实例,但它的行为必须与创建的实例相同

假设编译器和标准库的行为符合段落中的规定,并且没有执行不同但等效的操作,那么对于我的程序来说,唯一有效的初始化顺序似乎是初始化第一个源文件,然后初始化第二个源文件。否则,在尝试使用std::cout之前,它将不会被初始化

头文件:

#ifndef HEADER_H_
#define HEADER_H_

struct A {
  A(const char*);
  ~A();
  const char* v;
}

#endif
第一个源文件:

#include "header.h"
#include <iostream>

A::A(const char* val) : v{ val } {
  std::cout << v << "\n";
}
~A() {
  std::cout << "~" << v << "\n";
}

A a{ "a" };
A b{ "b" };
#include "header.h"

A c{ "c" };
A d{ "d" };

int main() {
}

在写这个问题时,我意识到答案包含在3.6.2/4中

实现定义了具有静态存储持续时间的非局部变量的动态初始化是否在main的第一个语句之前完成。如果初始化延迟到main的第一个语句之后的某个时间点,则应在首次odr使用与待初始化变量定义在同一转换单元中的任何函数或变量之前进行

这意味着,即使它决定只初始化第二个源文件,对
c
构造函数的调用将导致第一个源文件在实际执行
c
构造函数之前被初始化。这保证了静态初始化完成的顺序为:

  • ios_base::Init
  • a
  • b
  • c
  • d

  • 因为初始化顺序没有歧义,所以没有问题。

    TL;博士简而言之:每当您使用其中的一些声明时,Inlcude