我对以下代码感到有点困惑:
struct A {
std::atomic<int> a = 0;
};
哪个出错:
复制'std :: atomic'类型的成员子对象调用已删除的构造函数
但几乎相同的代码确实有效:
struct A {
std::atomic<int> a = {0};
};
Okey,如果第一个变体需要复制构造函数,那么它必须使用operator=()
。可是等等!这个运算符在没有复制构造函数的情况下完美地工作:
A a;
a.a = 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;
所以没有问题。