Does value initialization work for atomic objects?

By working here, I mean that std::atomic<T> a{} effectively zero initializes a . I always thought so and practically used it before. Before explaining my understanding of this, I want to show that at least gcc and clang do this in practice.

 #include <cstring> #include <atomic> #include <iostream> int main() { using atomic = std::atomic<int>; auto p = (atomic*)operator new(sizeof(atomic)); std::memset(p, -1, sizeof(atomic)); new(p) atomic{}; std::cout << p->load() << std::endl; } 

Pin 0 to gcc and clang .

Below is my explanation of why this should work (of course, you might think differently). The standard says that

In the following definitions of operations:

  • a refers to one of the atomic types.

[...]

 A::A() noexcept = default; 

Effects: leaves the atomic object in an uninitialized state. [Note: these semantics provide compatibility with C. - end note]

It basically says that the default constructor is trivial and does nothing. I am fine with this, but I do not see how this makes initializing the value inapplicable. According to cppref , value initialization effects include (highlight mine):

if T is a class type with a default constructor that is not user-provided or remote (that is, it can be a class with an implicit or default default constructor ), the zero object is initialized, and then initialized by default if it has a non-trivial constructor default;

std::atomic has a standard default constructor, so the object

  • with zero initialization and then
  • it is initialized by default if it has a non-trivial default constructor.

Clause 2 does not apply here, since the standard default constructor is trivial, but I do not see any statements that make clause 1 invalid. Did I understand correctly or is something missing?

+5
source share
1 answer

Ultimately, the essence of the case for the initialization of the value is in [dcl.init] / 7 , bullets 1 and 2:

To initialize an object of type type T means:

  • if T is a (possibly cv-qualified) class of type (Clause [class]) with a user-supplied constructor ([class.ctor]), then the default constructor for T is called (and initialization is poorly formed if T does not have an accessible constructor by default);
  • T is a (possibly cv-qualified) class of type non-union without a constructor provided by the user, then the object is initialized to zero and, if T is an implicitly declared default constructor, it is non-trivial that constructor.
  • ...

Which of the two cartridges above depends on which c'tor is provided by the user. What I do not remember in the comments to another answer is the subtleties = default; when applied to this. If we look at the definition given in [dcl.fct.def.default] / 4 (emphasis added):

Explicit default functions and implicitly declared functions are collectively referred to as default functions, and the implementation should provide them with implicit definitions ([class.ctor] [class.dtor], [class.copy]), which may mean their removal. A special member function is provided to the user if it is declared by the user and not explicitly defaulted or deleted by his first declaration. an explicitly default function provided by the user (i.e., explicitly by default after his first declaration) is defined at the point where he is clearly defaulted; if such a function is implicitly defined as deleted, the program is poorly formed. [Note: Declaring a function as the default after the first declaration can provide efficient execution and a concise definition, allowing a stable binary interface for an evolving code base. - final note]

We see that by default c'tor atomic not provided to the user , because it is declared as default, not declared, and then defined as default. Thus, the second bullet [dcl.init] / 7 is used, the object is initialized to zero, followed by a (non) call to the (trivial default) constructor that does nothing.

+5
source

Source: https://habr.com/ru/post/1275989/


All Articles