我想知道为什么委员会决定在定义析构函数时隐式删除移动构造函数。
#include <iostream>
#include <vector>
#include <memory>
struct A {
~A(){};
std::unique_ptr<int> a;
};
int main()
{
A a;
A b = std::move(a);
}
http://coliru.stacked-crooked.com/a/c0c067fc51260794
是否有任何utopic用例,其中“非默认移动成员”的规则有意义?
答案 0 :(得分:5)
逻辑是:如果你定义了一个暗示它在那里释放资源的析构函数,那么编译器生成的构造函数和赋值可能就不够了。
答案 1 :(得分:3)
我们的想法是,如果您发现需要为您的类声明析构函数或复制特殊成员,那么该类必须包含需要特殊处理的资源,因此隐式声明移动特殊成员可能是危险的,因为生成的代码可能导致不正确的行为。
一个简单的例子是
struct String
{
char *s = nullptr;
size_t size = 0;
String(char const* s); // makes a copy of the string
~String()
{
delete[] s;
}
};
如果标准允许隐式移动构造函数生成,它会做什么?它只是初始化目标对象中的s
和size
,但它不会将它们分别分配给源对象中的nullptr
和0
。这会导致源和目标对象的析构函数和未定义的行为双重删除。
隐式生成复制赋值运算符也会导致类似的问题。
请注意,对于上面的示例,C ++ 11也不推荐使用隐式生成的副本特殊成员。不幸的是,它们无法被定义为删除,因为它会破坏太多的代码。
如果类定义没有显式声明复制构造函数,则隐式声明非显式构造函数。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数被定义为已删除;否则,它被定义为默认。 如果类具有用户声明的复制赋值运算符或用户声明的析构函数,则不推荐使用后一种情况。