为什么在定义析构函数时隐式删除​​了移动构造函数

Gab*_*iel 0 c++ c++14 c++17

我想知道为什么委员会决定在定义析构函数时隐式删除​​移动构造函数.

#include <iostream>
#include <vector>
#include <memory>

struct A { 
  ~A(){}; 
  std::unique_ptr<int> a;
};


int main()
{
    A a;
    A b = std::move(a);
}
Run Code Online (Sandbox Code Playgroud)

http://coliru.stacked-crooked.com/a/c0c067fc51260794

有没有任何utopic用例,这个"非默认移动成员"的规则有意义吗?

Pra*_*ian 6

我们的想法是,如果您发现需要为类声明析构函数或复制特殊成员,则该类必须包含需要特殊处理的资源,因此隐式声明移动特殊成员可能很危险,因为生成的代码可能会导致不正确的行为。

一个简单的例子是

struct String
{
    char *s = nullptr;
    size_t size = 0;

    String(char const* s); // makes a copy of the string

    ~String()
    {
        delete[] s;
    }
};
Run Code Online (Sandbox Code Playgroud)

如果标准允许隐式移动构造函数生成,它会做什么?它只会在目标对象中初始化ssize,但不会将它们分别分配给源对象中的nullptr和。0这会导致源对象和目标对象的析构函数中的双重删除以及未定义的行为。

隐式生成复制赋值运算符也会导致类似的问题。


请注意,对于上面的示例,C++11 也已弃用复制特殊成员的隐式生成。不幸的是,它们不能被定义为已删除,因为它会破坏太多代码。

[类.copy.ctor]/6

如果类定义没有显式声明复制构造函数,则隐式声明非显式复制构造函数。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数被定义为已删除;否则,它被定义为默认值。 如果类具有用户声明的复制赋值运算符或用户声明的析构函数,则不推荐使用后一种情况。


Max*_*kin 5

逻辑是:如果你定义了一个暗示它在那里释放资源的析构函数,那么编译器生成的构造函数和赋值可能就不够了.