c++c++11c++17stdstdatomic

Indirect & Direct initialization of std::atomic in C++11/17. What are the differences?


On this CPP Con 2017 webinar, Fedor Pikus says: "it has to be direct initialization"

enter image description here This is the link to the webinar.

What are the differences between these initialization methods? (and subsequently, why it has to be a "direct" initialization? why "indirect" initialization is "NOT"?)

// C++17 Compiler

#include <atomic>

class Example
{
    std::atomic<bool> b1_ = false; // 1-h
    std::atomic<bool> b2_{ false }; // 2-h

    static void doSomethng()
    {
        std::atomic<bool> b1 = false; // 1-f
        std::atomic<bool> b2{ false }; // 2-f
        std::atomic<bool> b3(false); // 3-f

        // Do something
    }
};

Solution

  • std::atomic is not copyable or movable.

    Before C++17, the copy-initialization std::atomic<int> x = 0; would first construct a temporary std::atomic<int> from 0 and then direct-initialize x from that temporary. Without a move or copy constructor this would fail and so the line doesn't compile.

    std::atomic<int> x(0); however is direct-initialization and will just construct x with the argument 0 to the constructor.

    Since C++17 there is no temporary and x will directly be initialized by a constructor call with 0 as argument in any case and so there is no issue with std::atomic being non-movable. In that sense the slide is now out-dated.

    Even though the behavior is now the same for copy-initialization and direct-initialization in this case, there are still differences between the two in general. In particular direct-initialization chooses a constructor to initialize the variable directly by overload resolution while copy-initialization tries to find an implicit conversion sequence (possibly via converting constructor or conversion function with different overload resolution rules). Also, copy-initialization, in contrast to direct-initialization, does not consider constructors marked explicit.

    Regarding the code snippet in the question. 1-h and 1-f are copy-initialization as above. 3-f is direct-initialization as above. 2-h and 2-f are direct-list-initialization, which behaves different from both others in some cases, but here it has the same effect as direct-initialization with parentheses.

    Explaining all the differences between the initialization forms in general would take a while. This is famously one of the most complex parts of C++.