C++17 中不可复制变量的成员初始化
Member initialization for non-copyable variable in C++17
在对不可复制变量(如std::atomic<int>
)进行成员初始化时,根据答案here,需要使用direct-initialization
而不是copy-initialization
。但是,当我在 g++ 7.4.0
中打开 -std=c++17
时,似乎后者也能正常工作。
#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 以来行为发生了变化,要求 编译器省略 std::atomic<int> a = 0;
中的 copy/move 构造,即 guaranteed copy elision。
(强调我的)
Under the following circumstances, the compilers are required to omit the copy and move construction of class objects, even if the copy/move constructor and the destructor have observable side-effects. The objects are constructed directly into the storage where they would otherwise be copied/moved to. The copy/move constructors need not be present or accessible, as the language rules ensure that no copy/move operation takes place, even conceptually:
详细来说,std::atomic<int> a = 0;
执行copy initialization:
If T is a class type, and the cv-unqualified version of the type of other is not T or derived from T, or if T is non-class type, but the type of other is a class type, user-defined conversion sequences that can convert from the type of other to T (or to a type derived from T if T is a class type and a conversion function is available) are examined and the best one is selected through overload resolution. The result of the conversion, which is a prvalue temporary (until C++17)
prvalue expression (since C++17)
if a converting constructor was used, is then used to direct-initialize the object.
和
(强调我的)
if T is a class type and the initializer is a prvalue expression whose cv-unqualified type is the same class as T, the initializer expression itself, rather than a temporary materialized from it, is used to initialize the destination object
也就是说a
是直接从0
初始化的,没有temporary构造,也就不再是temporary 到 copy/move 来自.
在 C++17 之前,在概念上 std::atomic<int> a = 0;
需要从 0
构造临时 std::atomic
,然后临时用于复制构造 a
.
在C++17之前甚至允许copy elision,它被认为是一种优化:
(强调我的)
This is an optimization: even when it takes place and the copy/move (since C++11)
constructor is not called, it still must be present and accessible (as if no optimization happened at all), otherwise the program is ill-formed:
这就是为什么 gcc 在 pre-c++17 模式下为 std::atomic<int> a = 0;
触发诊断。
(强调我的)
Note: the rule above does not specify an optimization: C++17 core language specification of prvalues and temporaries is fundamentally different from that of the earlier C++ revisions: there is no longer a temporary to copy/move from. Another way to describe C++17 mechanics is "unmaterialized value passing": prvalues are returned and used without ever materializing a temporary.
顺便说一句:我想 g++ 6.5.0
和 -std=c++17
中有一个错误;并且在以后的版本中已经修复
Which one is correct here?
7.4.0 正确。在这种情况下可以省略副本,这就是它可以的原因。 (虽然这需要 c++17)。
(有关详细信息,请参阅 https://en.cppreference.com/w/cpp/language/copy_initialization)
在对不可复制变量(如std::atomic<int>
)进行成员初始化时,根据答案here,需要使用direct-initialization
而不是copy-initialization
。但是,当我在 g++ 7.4.0
中打开 -std=c++17
时,似乎后者也能正常工作。
#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 以来行为发生了变化,要求 编译器省略 std::atomic<int> a = 0;
中的 copy/move 构造,即 guaranteed copy elision。
(强调我的)
Under the following circumstances, the compilers are required to omit the copy and move construction of class objects, even if the copy/move constructor and the destructor have observable side-effects. The objects are constructed directly into the storage where they would otherwise be copied/moved to. The copy/move constructors need not be present or accessible, as the language rules ensure that no copy/move operation takes place, even conceptually:
详细来说,std::atomic<int> a = 0;
执行copy initialization:
If T is a class type, and the cv-unqualified version of the type of other is not T or derived from T, or if T is non-class type, but the type of other is a class type, user-defined conversion sequences that can convert from the type of other to T (or to a type derived from T if T is a class type and a conversion function is available) are examined and the best one is selected through overload resolution. The result of the conversion, which is a
prvalue temporary (until C++17)
prvalue expression (since C++17)
if a converting constructor was used, is then used to direct-initialize the object.
和
(强调我的)
if T is a class type and the initializer is a prvalue expression whose cv-unqualified type is the same class as T, the initializer expression itself, rather than a temporary materialized from it, is used to initialize the destination object
也就是说a
是直接从0
初始化的,没有temporary构造,也就不再是temporary 到 copy/move 来自.
在 C++17 之前,在概念上 std::atomic<int> a = 0;
需要从 0
构造临时 std::atomic
,然后临时用于复制构造 a
.
在C++17之前甚至允许copy elision,它被认为是一种优化:
(强调我的)
This is an optimization: even when it takes place and the copy/
move (since C++11)
constructor is not called, it still must be present and accessible (as if no optimization happened at all), otherwise the program is ill-formed:
这就是为什么 gcc 在 pre-c++17 模式下为 std::atomic<int> a = 0;
触发诊断。
(强调我的)
Note: the rule above does not specify an optimization: C++17 core language specification of prvalues and temporaries is fundamentally different from that of the earlier C++ revisions: there is no longer a temporary to copy/move from. Another way to describe C++17 mechanics is "unmaterialized value passing": prvalues are returned and used without ever materializing a temporary.
顺便说一句:我想 g++ 6.5.0
和 -std=c++17
中有一个错误;并且在以后的版本中已经修复
Which one is correct here?
7.4.0 正确。在这种情况下可以省略副本,这就是它可以的原因。 (虽然这需要 c++17)。
(有关详细信息,请参阅 https://en.cppreference.com/w/cpp/language/copy_initialization)