我想知道复制/move 省略何时适用(或允许应用)显式删除复制/move 构造函数和非删除复制/move 构造函数。具体内容如下:
显式
删除
的复制构造函数或 move 构造函数是否可以被删除?尝试从另一个相同类型的对象或临时对象构造对象是否可以通过跳过删除复制函数和/或删除 move 函数来成功?这是 VC12 中发生的情况(我不确定是否有禁用复制/move 省略的选项):
#include <iostream> struct Foo { Foo() { std::cout << "default ctor\n"; } Foo(Foo const&) = delete; Foo(Foo&&) = delete; }; int main() { // ----Output------ Foo{ Foo() }; // "default ctor" Foo f; // "default ctor" Foo{ std::move(f) }; // error C2280: 'Foo::Foo(Foo &&)' : attempting to reference a deleted function Foo{ f }; // error C2280: 'Foo::Foo(const Foo &)' : attempting to reference a deleted function }
尽管 IntelliSense 提示
Foo{ Foo() };
:Error: function “Foo::Foo(Foo &&)” ... 无法引用 – 它已被删除function
,编译器不会在那里提示,因此该行仍然可以编译。为什么
Foo{ Foo() };
可以工作,但Foo{ std::move(f) };
不行?如果一个调用忽略了 move ctor,那么另一个调用也不应该这样做吗?为什么
Foo{ Foo() };
可以工作,但Foo{ f };
不行?这种选择性看起来是任意的。这种右值引用相对于 const 引用的任意偏好(反之亦然)似乎不适用于非构造方法;在调用中,如果delete
d 重载的重载解析优先级高于非delete
d 重载,则delete
d 一个会阻塞非delete
d 一个,从而导致编译器错误:struct Bar { void g(int const&) {} void g(int&&) = delete; }; //… Bar b; b.g(2); //error C2280: 'void Bar::g(int &&)' : attempting to reference a deleted function // ^ Would have compiled had function `g(int&&)` been commented out.
根据该逻辑,当
delete
dFoo(Foo&&)
争论不是暂时的;在这种情况下,Foo(Foo&&)
的重载解析优先级将低于Foo(Foo const&)
。我在 g++ 4.8 中尝试了相同的
Foo
示例,禁用复制省略(通过标志-fno-elide-constructors
),然后再次启用它。两项 g++ 试验均给出:错误:对
和Foo{ Foo() };
使用已删除的函数 'Foo::Foo(Foo&&)'错误:对
Foo{ f };
使用已删除的函数 'Foo::Foo(const Foo&)'哪个编译器是正确的?
最佳答案
VC++女士有一个非常古老的众所周知的错误。来自 C++ 标准
[ Note: This two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided. —end note ]
关于c++ - 复制/move 省略与显式删除的复制/move 构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20589622/