根据标准,
如果类 X 的定义没有显式声明移动构造函数,当且仅当
— X 没有用户声明的复制构造函数,
— X 没有用户声明的复制赋值运算符,
— X 没有用户声明的移动赋值运算符,并且
— X 没有用户声明的析构函数。
现在以下无法编译
# include <utility>
class Foo
{
public:
Foo() = default;
Foo(Foo const &) = delete;
};
int main()
{
Foo f;
Foo g(std::move(f)); // compilation fails here
return 0;
}
所以似乎删除的函数被认为是用户定义的,这是有道理的(它不是它的默认实现)。但是,在那种特殊情况下,如何删除复制构造函数/赋值混乱默认移动构造函数/赋值?
我认为这个问题具有实际意义,因为手动生成和 esp。维护这些默认函数很容易出错,同时(正义的)增加使用诸如 std::unique_ptr
之类的类,因为类成员使不可复制的类比过去更常见是。
原文由 P-Gn 发布,翻译遵循 CC BY-SA 4.0 许可协议
user-declared
表示 _用户提供_(由用户 定义)、 _显式默认_(= default
)或 _显式删除_(= delete
) (例如您的移动构造函数)。因此,在您的情况下, 是 的,移动构造函数被 隐式 删除,因为复制构造函数被 显式 删除(因此 user-declared )。
不会,但是标准并没有区分这种情况和复杂的情况。
最短的答案是, 隐式 定义的移动构造函数和 显式 删除的复制构造函数在某些情况下 可能 是危险的,当你有一个 用户定义的 析构函数而没有 用户定义的 复制构造函数时也是如此(参见 规则三/五/零)。现在,您可以争辩说用户定义的析构函数不会删除复制构造函数,但这只是语言中的一个 _缺陷_,无法删除,因为它会破坏许多旧(坏)程序。引用 Bjarne Stroustrup 的话:
您可以在 N3174=10-0164 中阅读有关此内容的更多信息。
请注意,大多数人都遵循 三/五/零的规则, 我认为你应该这样做。通过隐式删除默认的移动构造函数,标准是“保护”您免受错误的影响,并且在某些情况下应该通过删除复制构造函数来保护您很长时间(参见 Bjarne 的论文)。
感兴趣的可以继续阅读:
将移动构造函数标记为显式默认将解决此问题:
您会得到一个具有默认移动构造函数的不可复制对象,并且在我看来,这些显式声明比隐式声明更好(例如,仅将移动构造函数声明为
default
而不删除复制构造函数)。