C++ 下面的计划如何保证那里';将只是对象的一个定义,是吗。。。?
您将在哪个标题下找到以下语句?: 最后,C++ 下面的计划如何保证那里';将只是对象的一个定义,是吗。。。?,c++,initialization,iostream,C++,Initialization,Iostream,您将在哪个标题下找到以下语句?: 最后,提供了八个标准全局对象(cin、, 库特等)。要正确执行此操作,此标题还提供 和标题的内容,但没有其他内容。这个 此标题的内容如下所示 #包括 #包括 名称空间标准 { 外间流cin; 外部环境; .... //下文对此进行解释 静态ios_base::Init _foo;//不是它的真名 } 现在,前面提到的运行时惩罚:全局对象必须 在您自己的任何代码使用它们之前进行初始化;这是 由标准保证。与任何其他全局对象一样,它们必须是 初始化一次且仅初始化一次
提供了八个标准全局对象(cin、,
库特等)。要正确执行此操作,此标题还提供
和
标题的内容,但没有其他内容。这个
此标题的内容如下所示
#包括
#包括
名称空间标准
{
外间流cin;
外部环境;
....
//下文对此进行解释
静态ios_base::Init _foo;//不是它的真名
}
现在,前面提到的运行时惩罚:全局对象必须
在您自己的任何代码使用它们之前进行初始化;这是
由标准保证。与任何其他全局对象一样,它们必须是
初始化一次且仅初始化一次。这通常是通过一个
与上面的构造类似,嵌套类ios_base::Init是
正是出于这个原因在标准中规定的
它是如何工作的?因为标题包含在任何
代码中,_foo对象是在任何对象之前构造的。
(全局对象按声明顺序构建,以及
构造函数第一次运行时
设置了八个流对象
我的问题:当我在几个
.cpp
文件中包含头文件
时,上面的方案如何保证对象cin
,cout
等只有一个定义 这并不能保证这一点。只需在作为库的一部分的.cpp文件中定义一次流对象,即可解决单定义问题。问题中的代码只包含标准流的声明
可以保证的是,对象在使用之前将被初始化。C++中的全局对象的一个问题是,尽管它们在每个.CPP文件中都是按顺序初始化的,但我们不知道链接器将从单独的文件中放置对象的顺序。如果一个对象在初始化之前尝试使用另一个对象,并且我们不知道确切的顺序,那么这可能会导致问题-请参阅
这里使用的一种解决方法是在声明流对象的头中放置Init
对象。因为在使用流之前必须包含头,所以我们知道这个Init
对象将位于文件的顶部,因此在可能使用流的其他对象之前构造
现在,Init
类的构造函数负责流对象的初始化。这必须尽早完成,而且只需一次。具体如何操作取决于每个实现,但代码提示使用计数器跟踪创建的Init
对象的数量(可能会特别处理第一个)
这只是一种方法,只使用标准语言。有些实现还有其他技巧,比如s或指令,以说服链接器将库代码放在用户代码之前。在这种情况下,它只是神奇地工作,没有使用
Init
类。这个“一个定义”并不有趣——它只是(编译的)标准库的一部分。有趣的是“一次初始化”。(我认为这项技术被称为。)AFAIK、cout
、cin
等。对象只是在标题中声明为extern
,实际的定义在标准库的文件中。现在,ios\u base::Init
被声明为static
,因此每个翻译单元都有自己的副本。Init
对象的构造函数/析构函数执行某种引用计数,以了解何时初始化/销毁标准流对象。至少你说的我都明白了。我不明白的是,当
包含在几个.cpp
文件中时,ios_base::Init
如何避免全局对象cin,cout,….的多个定义。就像我说的,
中没有定义它们,它们只是声明的。@jrok我将重新表述我的问题:上面的方案如何保证全局对象cin,cout,…,只有一个定义<代码>可以保证的是,对象在使用之前将被初始化。C++中的全局对象的一个问题是,尽管它们在每个.CPP文件中都是按顺序初始化的,但我们不知道链接器将从单独的文件中放置对象的顺序。如果一个对象在初始化之前尝试使用另一个对象,这可能会导致问题,我们不知道确切的顺序。据我所知,这个问题已经在C++11中解决了,至少根据这个答案,唯一的区别是在C++11中,实现的行为应该像构造Init
对象一样。这也是它在C++03中的工作方式,只是没有详细说明(因为它被认为是显而易见的:-)。请参见只需在作为库的一部分的.cpp文件中定义一次流对象,即可解决一个定义问题。
您是否有任何参考资料支持这一点?标准对此有什么规定吗?
#include <ostream>
#include <istream>
namespace std
{
extern istream cin;
extern ostream cout;
....
// this is explained below
static ios_base::Init __foo; // not its real name
}