Variable templates and std::cout — order of construction

不问归期 提交于 2019-12-10 01:04:43

问题


It looks like we can safely use std::cout object in constructors of objects with static storage duration as stated in this question.

However, I'm not entirely sure that we can safely use them in case of variable templates:

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

This code crashes in clang (live example) and I'm not sure whether it's a bug or not.


回答1:


As explained in that question, one effect of

#include <iostream>

is the equivalent of defining a global variable

static std::ios_base::Init __init;

which (assuming that you include it at the start of the TU) guarantees that for all static storage duration objects with ordered initialization in the same TU, the stream objects have been set up.

However, explicitly and implicitly instantiated template specializations have unordered initialization ([basic.start.dynamic]/1)1:

Dynamic initialization of a non-local variable with static storage duration is unordered if the variable is an implicitly or explicitly instantiated specialization, and otherwise is ordered [note omitted]. Variables with ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit.

And since

If a program starts a thread, the subsequent unordered initialization of a variable is unsequenced with respect to every other dynamic initialization. Otherwise, the unordered initialization of a variable is indeterminately sequenced with respect to every other dynamic initialization.

there's no guarantee that the stream objects have been initialized at the time the variable template specialization x<Test> is initialized.

In this case, as one of the possible executions results in undefined behavior (using the stream objects before they are initialized), the behavior of the entire program is undefined (see [intro.execution]/5).

The fix is to construct a std::ios_base::Init object yourself in Test's constructor.


1 This is actually underspecified for variable templates when C++14 was published, but it's always been the intent.



来源:https://stackoverflow.com/questions/37705923/variable-templates-and-stdcout-order-of-construction

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!