为什么在定义析构函数时隐式删除移动构造函数
Why is the move constructor implicitly deleted when a destructor is defined
我想知道为什么委员会决定在定义析构函数时隐式删除移动构造函数。
#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
是否有任何乌托邦用例,这个规则"不默认移动成员"是有意义的?
逻辑是:如果您定义一个析构函数,暗示它在那里释放资源,那么编译器生成的构造函数和赋值可能是不够的。
这种想法是,如果您发现需要为类声明析构函数或复制特殊成员,则该类必须包含需要特殊处理的资源,因此隐式声明移动特殊成员可能很危险,因为生成的代码可能会导致不正确的行为。
一个简单的例子是
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 也弃用了复制特殊成员的隐式生成。不幸的是,它们不能定义为已删除,因为它会破坏太多代码。
[class.copy.ctor]/6
如果类定义未显式声明复制构造函数,则隐式声明非显式构造函数。如果类定义声明移动构造函数或移动赋值运算符,则隐式声明的复制构造函数定义为已删除;否则,它被定义为默认值。 如果类具有用户声明的复制赋值运算符或用户声明的析构函数,则不推荐使用后一种情况。
相关文章:
- std::vector::p ush_back() 不会在 MSVC 上编译具有已删除移动构造函数的对象
- 移动赋值运算符;尝试引用已删除的函数.我该如何解决这个问题?
- 具有已删除移动和复制构造函数的类的就地构造
- 我什么时候会默认(而不是删除)基类中的复制和移动操作
- 将内容从第一个文件("constituencies")移动到第二个文件("temp")并在之后重命名时,我的文件被删除
- 为什么在删除"移动构造函数"时使用"复制构造函数"?
- 当存在用户定义的移动分配运算符时,已删除模板移动分配运算符
- 默认移动成员定义为已删除,而未定义特殊成员?
- 为什么定义移动构造函数会删除移动赋值运算符
- 为什么当我不移动任何东西时,clang 会抱怨删除移动 ctor?
- 为什么在定义析构函数时隐式删除移动构造函数
- 从rvalue删除移动构造函数和构造对象
- 为什么删除移动构造函数会导致编译错误
- 为什么'std::p air'允许使用用户定义的已删除移动构造函数从类类型的右值初始化?
- 当使用三元运算符并删除移动/复制CTOR时,Visual Studio不执行RVO
- 为什么C++允许您移动包含已删除移动操作的对象的类
- 已显式删除移动构造函数
- GCC C++11 删除移动可分配类的副本分配会阻止 std::sort 编译
- 返回带有已删除移动/复制 ctor 的类型临时
- 消除默认/删除移动/复制语义中涉及的样板的好方法是什么