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

时间:2018-03-21 08:00:19

标签: c++ c++11 language-lawyer atomic value-initialization

通过工作,我的意思是std::atomic<T> a{}有效地零初始化a。我一直在这么想,直到this一直在使用它。在解释我对此的理解之前,我想表明,至少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;
}

gccclang上的输出为0

以下是我解释为什么这应该有效(当然,你可能会另有想法)。标准说

  

在以下操作定义中:

     
      
  • a A指的是原子类型之一。
  •   
     

[...]

A::A() noexcept = default;
     

效果:使原子对象处于未初始化状态。 [注意:这些语义确保与C的兼容性。 - 结束注释]

它基本上说默认构造函数是微不足道的,什么都不做。我对此很好,但我不知道这是如何使值初始化不适用的。根据{{​​3}},值初始化的影响包括(强调我的):

  

如果T是具有默认构造函数的类类型,则两者都不是   用户提供或删除(也就是说,它可能是一个带有   对象是隐式定义的或默认的默认构造函数)   零初始化然后如果它有一个默认初始化   非平凡的默认构造函数;

std::atomic有一个默认的默认构造函数,因此对象是

  1. 零初始化然后
  2. 如果它具有非平凡的默认构造函数,则默认初始化。
  3. 第2点不适用于此处,因为默认的默认构造函数是微不足道的,但我没有看到任何使第1点无效的语句。我的理解是正确还是我错过了什么?

1 个答案:

答案 0 :(得分:6)

最终,价值初始化案例的关键在于[dcl.init]/7,子弹1和2:

  

对T类型的对象进行值初始化意味着:

     
      
  • 如果T是一个(可能是cv限定的)类类型(Clause [class]),带有用户提供的构造函数([class.ctor]),那么默认构造函数   调用T(如果T没有,则初始化是错误的   access default constructor);
  •   
  • T是一个(可能是cv限定的)非联合类类型,没有用户提供的构造函数,那么该对象是零初始化的,如果   T隐式声明的默认构造函数是非平凡的   构造函数被调用。
  •   
  • ...
  •   

上述两个子弹中的哪一个取决于用户提供的c。在对其他答案的评论中,我没有记住的是= default;在应用于此时的复杂性。如果我们看一下[dcl.fct.def.default]/4(强调我的)给出的定义:

  

明确默认的函数和隐式声明的函数   统称为违约函数,并实施   为它们提供隐式定义([class.ctor] [class.dtor],   [class.copy]),这可能意味着将它们定义为已删除。 一个特别的   成员函数是用户提供的,如果它是用户声明的而不是   明确默认或删除其第一个声明。 :一种   用户提供的显式默认功能(即明确地)   在第一次声明之后违约在其中定义   它被明确默认;如果隐含地定义了这样的函数   如删除,该程序是不正确的。 [注意:将函数声明为   在第一次声明之后默认可以提供有效的执行   和简洁的定义,同时启用稳定的二进制接口   不断发展的代码库。 - 结束说明]

我们发现atomic 的默认c来源不是用户提供的,因为它被声明为默认值,而不是声明然后定义为默认值。所以[dcl.init] / 7的第二个子弹是适用的,该对象是零初始化的,然后是(非)调用(平凡的默认)构造函数,它什么都不做。

相关问题