我正在尝试使用此代码来演示复制构造函数的用法。我的假设是,当我有一个按值返回的函数时,默认情况下,我的编译器将执行对象的移动。但是当move-constructor不可用时,编译器将复制(在C ++ 03中,编译器在返回by-value时会复制)。那么为什么在下面的例子中编译器会尝试调用显式删除的move-constructor而不是可用的copy-constructor呢?我正在GCC 4.7.2中编译它。
struct S
{
S() = default;
S(S const &) = default;
S(S&&) = delete;
};
S f() { return S{}; }
int main()
{
f();
}
prog.cpp:在函数
‘S f()’
中:
prog.cpp:8:18:错误:使用已删除的函数‘S::S(S&&)’
prog.cpp:5:5:错误:在这里宣布
答案 0 :(得分:39)
删除的移动成员是邪恶的。他们不是非法的,因为有一天,有人会为他们找到一个聪明的用途。但我还没有看到好用。
删除特殊成员与没有特殊成员不同。没有哪个比移动构造函数和移动赋值运算符更明显。
当存在时,无论是删除,默认还是用户定义,移动构造函数和移动赋值运算符都参与重载解析。这意味着他们与特殊的副本成员“竞争”。复制成员通常会使用常量值,而移动成员则会吸引左值。
从函数返回本地类型时(当本地类型与返回类型的un-cv限定类型相同时),return语句首先将返回表达式视为右值,并且仅当它不能找到合适的构造函数,然后将其视为左值。即匹配正确的构造函数以从函数返回本地对象是一个两阶段操作。
如果你根本没有移动构造函数(甚至没有删除),但是你有一个普通的复制构造函数(取一个const&),那么return语句中的rvalue将与复制构造函数匹配。 / p>
当你做有一个移动构造函数时,即使它被标记为已删除,return语句中的rvalue也会发现移动构造函数比复制构造函数更匹配。
<强>摘要强>
除非您确实知道自己在做什么,否则永远不会删除移动成员。如果您不希望您的类型可移动,请不要定义移动成员并确保您确实声明了复制成员,即使复制成员是=default
'd。
<强>更新强>
我认为很难从标准中提供删除内容的引用 不行吗? - DyP
8.4.3删除定义[dcl.fct.def.delete]
2隐式引用已删除函数的程序 明确地,除了宣布它之外,是不正确的。 [注意:这个 包括隐式或显式调用函数并形成一个 指向函数的指针或指向成员的指针。它甚至适用于 表达式中没有潜在评估的引用。如果一个 函数重载,仅在函数为时才引用 由重载决议选择。 - 结束说明]
更新2
12.8复制和移动类对象[class.copy]
9如果类X的定义没有明确声明移动 构造函数,只有当一个隐式声明为默认值 如果
- X没有用户声明的复制构造函数,
- X没有用户声明的复制赋值运算符
- X没有用户声明的移动赋值运算符和
- X没有用户声明的析构函数。
[注意:当没有隐式声明移动构造函数或 显式提供,否则将调用的表达式 移动构造函数可能会调用复制构造函数。 - 结束说明]