值初始化是否适用于原子对象?

Does value initialization work for atomic objects?

这里的工作,我的意思是std::atomic<T> a{}有效地零初始化a。一直这么想,一直到才开始实际使用。在解释我对此的理解之前,我想表明,至少 gcc 和 clang 在实践中是这样做的。

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

两个 gcc and clang 上的输出都是 0

以下是我对为什么这应该起作用的解释(当然,您可能不这么认为)。标准说

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 ]

它基本上是说默认构造函数是微不足道的,什么都不做。我对此没有意见,但我不明白这如何使值初始化不适用。根据cppref,值初始化的影响包括(强调我的):

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有默认的默认构造函数,所以对象是

  1. 零初始化然后
  2. 如果它有一个非平凡的默认构造函数,它就是默认初始化的。

第 2 点在这里不适用,因为默认的默认构造函数是微不足道的,但我没有看到任何使第 1 点无效的语句。我的理解正确还是我遗漏了什么?

最终值初始化情况的症结在[dcl.init]/7,要点 1 和 2:

To value-initialize an object of type T means:

  • if T is a (possibly cv-qualified) class type (Clause [class]) with a user-provided constructor ([class.ctor]), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
  • T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, if T's implicitly-declared default constructor is non-trivial, that constructor is called.
  • ...

应用上面两个项目符号中的哪一个取决于 c'tor 是 user-provided。我在对其他答案的评论中不记得的是 = default; 应用于该问题时的复杂性。如果我们看一下 [dcl.fct.def.default]/4 给出的定义(强调我的):

Explicitly-defaulted functions and implicitly-declared functions are collectively called defaulted functions, and the implementation shall provide implicit definitions for them ([class.ctor] [class.dtor], [class.copy]), which might mean defining them as deleted. A special member function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration. A user-provided explicitly-defaulted function (i.e., explicitly defaulted after its first declaration) is defined at the point where it is explicitly defaulted; if such a function is implicitly defined as deleted, the program is ill-formed. [ Note: Declaring a function as defaulted after its first declaration can provide efficient execution and concise definition while enabling a stable binary interface to an evolving code base. — end note ]

我们看到 atomic 的默认 c'tor 不是用户提供的 ,因为它被声明为默认,而不是被声明然后定义为违约。所以 [dcl.init]/7 的第二个项目符号是适用的,对象是 zero-initialized,然后是(非)调用(普通默认)构造函数,它什么也不做。