我想知道copy / move elision何时应用(或允许应用)显式delete
d复制/移动构造函数和非delete
d复制/移动构造函数。以下是具体内容:
明确delete
d复制ctor或移动ctor是否可以省略?是否试图通过跳过delete
d copy ctor和/或delete
d move ctor来构建来自另一个同类型对象或临时对象的对象?
以下是VC12中发生的情况(我不确定是否有禁用复制/移动省略的选项):
#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 &&)” ... cannot be referenced – it is a deleted function
,编译器也不会抱怨,因此该行仍在编译。
为什么Foo{ Foo() };
有效,而Foo{ std::move(f) };
无效?如果一个电话忽略了移动ctor,那么不应该是另一个吗?
为什么Foo{ Foo() };
有效,而Foo{ f };
无效?这种选择性看似随意。 rvalue引用与const引用的任意偏好(反之亦然)似乎不适用于非ctor方法;在调用中,如果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
d Foo(Foo&&)
不是临时的时,Foo(Foo const&)
Foo(Foo&&)
不应阻止对Foo(Foo const&)
的调用;在这种情况下,Foo
的重载决策优先级低于-fno-elide-constructors
。
我在g ++ 4.8中尝试了同样的error: use of deleted function 'Foo::Foo(Foo&&)'
示例,禁用了复制省略(通过标记Foo{ Foo() };
)并再次启用它。两个g ++试验都给出了:
error: use of deleted function 'Foo::Foo(const Foo&)'
和的 Foo{ f };
{{1}}
{{1}}
哪种编译器正确?
答案 0 :(得分:4)
VC ++女士有一个很老的知名bug。来自C ++标准
[注意:必须执行此两阶段重载决策 无论是否会发生复制。它决定了 如果未执行elision则调用的构造函数,以及所选的 即使呼叫被省略,也必须可以访问构造函数。 - 后注]