为什么就地成员初始化在C ++ 11中使用复制构造函数?

时间:2014-02-11 17:18:08

标签: c++ c++11 initialization atomic copy-constructor

我对以下代码感到有点困惑:

struct A {
  std::atomic<int> a = 0;
};

哪个出错:

  

复制'std :: atomic'类型的成员子对象调用已删除的构造函数

但几乎相同的代码确实有效:

struct A {
  std::atomic<int> a = {0};
};

Okey,如果第一个变体需要复制构造函数,那么它必须使用operator=()。可是等等!这个运算符在没有复制构造函数的情况下完美地工作:

A a;
a.a = 1;

任何人都可以解释如何在简单操作方面扩展两个就地初始化吗?为什么第一个需要复制构造函数?

1 个答案:

答案 0 :(得分:6)

让我们考虑第一种情况

struct A {
  std::atomic<int> a = 0;
};

要使此初始化成功,需要有一个可访问的复制构造函数。但是复制构造函数被定义为已删除。

atomic(const atomic&) = delete;

因此编译器会发出错误。

在第二种情况下

struct A {
  std::atomic<int> a = {0};
};

使用初始化列表时,不需要复制构造函数。编译器搜索一个接受一个int参数的构造函数,这样的构造函数确实存在,因此调用它。

constexpr atomic(T) noexcept;

或者是否将模板参数替换为int

constexpr atomic(int) noexcept;

根据C ++标准,如果一个类没有构造函数,其第一个参数类型为std :: initializer_list(当指定了初始化列表时),那么

  

3定义了对象或类型T的引用的列表初始化   如下:......

     

否则,如果T是类类型,则考虑构造函数。该   列举了适用的构造函数,并选择最佳构造函数   通过重载决议(13.3,13.3.1.7)。如果缩小   转换(见下文)是转换任何参数所必需的,   该计划格式不正确。

在最后一种情况下

A a;
a.a = 1;

这使用赋值运算符

T operator=(T) noexcept;

或者是否将模板参数替换为int

int operator=(int) noexcept;

所以没有问题。