mercredi 21 mars 2018

Does value initialization work for atomic objects?

By work here, I take to mean that std::atomic<T> a{} effectively zero initializes a. I have always been thinking so and have been practically using it until this. Before explaining my understanding of this, I want to show that, at the very least, gcc and clang are doing it 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;
}

The output is 0 on both gcc and clang.

Following is my explanation of why this should work (you may think otherwise, of course). The standard says that

In the following operation definitions:

  • an A refers to one of the atomic types.

[...]

A::A() noexcept = default;

Effects: leaves the atomic object in an uninitialized state. [ Note: These semantics ensure compatibility with C. — end note ]

It basically says that the default constructor is trivial and does nothing. I'm OK with this, but I don't see how this makes value initialization non-applicable. According to cppref, the effects of value initialization include (emphasis mine):

if T is a class type with a default constructor that is neither user-provided nor deleted (that is, it may be a class with an implicitly-defined or defaulted default constructor), the object is zero-initialized and then it is default-initialized if it has a non-trivial default constructor;

std::atomic has a defaulted default constructor, so the object is

  1. zero-initialized and then
  2. it is default-initialized if it has a non-trivial default constructor.

Point 2 doesn't apply here since the defaulted default constructor is trivial, but I don't see any statement that renders point 1 in-effective. Is my understanding correct or am I missing something?

Aucun commentaire:

Enregistrer un commentaire