【问题标题】:Variable templates and std::cout -- order of construction变量模板和 std::cout -- 构造顺序
【发布时间】:2016-10-08 22:10:15
【问题描述】:

看起来我们可以在具有静态存储持续时间的对象的构造函数中安全地使用std::cout 对象,如question 中所述。

但是,我不完全确定在变量模板的情况下我们可以安全地使用它们:

#include <iostream>

template<class T>
T x = T{};

void foo()
{
    class Test
    {
    public:
        Test() { std::cout << "Test::Test\n"; }
    };

    Test t = x<Test>;
}


int main()
{
    std::cout << "main\n";
}

此代码在 clang (live example) 中崩溃,我不确定它是否是错误。

【问题讨论】:

  • 适用于 GCC。也许这是clang中的一个错误?
  • @Cornstalks 也许吧。但也许这只是一种未指明的行为?

标签: c++ c++11 c++14 c++17


【解决方案1】:

正如该问题中所解释的,

#include <iostream>

相当于定义一个全局变量

static std::ios_base::Init __init;

其中(假设您将其包含在 TU 的开头)保证对于在同一 TU 中具有 有序 初始化的所有静态存储持续时间对象,流对象已被设置。

但是,显式和隐式实例化的模板特化具有无序初始化 ([basic.start.dynamic]/1)1

使用静态存储动态初始化非局部变量 如果变量是隐式或显式的,则持续时间是无序的 实例化的特化,否则是有序的 [注意省略]。在单个翻译单元中定义的具有有序初始化的变量应按照它们在翻译单元中的定义顺序进行初始化。

因为

如果一个程序启动了一个线程,后续的无序初始化 一个变量相对于其他所有动态都是无序的 初始化。否则,变量的无序初始化 相对于其他所有动态是不确定的 初始化。

无法保证在变量模板特化 x&lt;Test&gt; 初始化时已初始化流对象。

在这种情况下,由于其中一种可能的执行会导致未定义的行为(在初始化之前使用流对象),因此整个程序的行为是未定义的(请参阅[intro.execution]/5)。

解决方法是在Test 的构造函数中自己构造一个std::ios_base::Init 对象。


1 这实际上在 C++14 发布时没有为变量模板指定,但它一直是本意。

【讨论】:

  • 所以即使对于那些在同一个翻译单元中定义的对象,它们也有无序初始化?
  • @FrozenHeart 是的。无论如何,不​​同的 TU 之间没有排序。
  • 非常感谢。那么下一个问题——stackoverflow.com/questions/37706549/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-04
  • 2015-04-07
  • 2013-09-15
相关资源
最近更新 更多