对不可复制变量(例如std::atomic<int>
)执行成员初始化时,需要使用direct-initialization
而不是copy-initialization
根据此处的答案。然而,当我打开-std=c++17
的g++ 7.4.0
,似乎后者也是行之有效的。
#include <atomic>
class A {
std::atomic<int> a = 0; // copy-initialization
std::atomic<int> b{0}; // direct-initialization
};
$ g++ -c atomic.cc -std=c++11 // or c++14
atomic.cc:4:26: error: use of deleted function ‘std::atomic<int>::atomic(const std::atomic<int>&)’
std::atomic<int> a = 0; // copy-initialization
$ g++ -c atomic.cc -std=c++17
// no error
与编译时,它也没有g++ 6.5.0
,甚至有-std=c++17
。这里哪一个是正确的?
自C ++ 17开始,行为发生了变化,这要求编译器省略in /的复制/移动构造std::atomic<int> a = 0;
,即保证复制省略。
(强调我的)
在以下情况下,即使复制/移动构造函数和析构函数具有明显的副作用,也要求编译器忽略类对象的复制和移动构造。这些对象直接构造到存储中,否则会将它们复制/移动到其中。复制/移动构造函数不需要存在或不可访问,因为语言规则可确保不会进行复制/移动操作,即使在概念上也是如此:
详细地,std::atomic<int> a = 0;
执行复制初始化:
如果T是类类型,并且other的cv不合格版本不是T或不是从T派生的,或者T是非类类型,但是other的类型是类类型,则用户定义的转换序列可以将其他类型转换为T(如果T是类类型并且可以使用转换函数,则可以转换为从T派生的类型),然后通过重载分辨率选择最佳的。转换结果(
prvalue temporary (until C++17)
prvalue expression (since C++17)
如果使用了转换构造函数,则为a)然后用于直接初始化对象。
和
(强调我的)
如果T是类类型,并且初始化程序是prvalue表达式,其cv不合格类型与T是同一类,则初始化程序表达式本身(而不是从其实例化的)用于初始化目标对象
这意味着a
可以0
直接初始化,没有临时构造,再也没有临时要复制/移动。
在C ++ 17之前,概念上std::atomic<int> a = 0;
需要std::atomic
从中构造一个临时文件0
,然后将该临时文件用于copy-construct a
。
在C ++ 17之前甚至允许复制省略,它被认为是一种优化:
(强调我的)
这是一种优化:即使发生并且
move (since C++11)
未调用copy / 构造函数,它也必须存在并且可以访问(好像根本没有优化发生),否则程序格式错误:
这就是为什么gcc在c ++ 17之前的模式下触发的诊断的原因std::atomic<int> a = 0;
。
(强调我的)
注意:上面的规则未指定优化:prvalues和temporaries的C ++ 17核心语言规范与早期C ++修订版的根本不同:不再需要从中复制/移动的临时属性。描述C ++ 17机制的另一种方法是“未实现的值传递”:prvalue的返回和使用无需实现一个临时值。
顺便说一句:我认为g++ 6.5.0
with中有一个错误-std=c++17
;并且已在更高版本中修复。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句