为什么插入用户定义的析构函数需要用户定义的复制构造函数

时间:2017-03-01 15:22:29

标签: c++ c++11 destructor copy-constructor unique-ptr

以下代码编译:

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

using namespace std;

class container
{
public:
    container(){}
    ~container(){}
};

class Ship
{
public:
    Ship(){}
    //Ship(const Ship & other){cout<<"COPY"<<endl;}
    //~Ship(){}

    std::unique_ptr<container> up;
};

Ship buildShip()
{
    Ship tmp;
    return tmp;
}

int main(int argc, char *argv[])
{
    return 0;
}

但是如果我们包含用户定义的析构函数~Ship(){},那么只有在我们还包含用户定义的复制构造函数Ship(const Ship & other){cout<<"COPY"<<endl;}

时才会编译代码

简而言之:

编译:

Ship(){}
//Ship(const Ship & other){cout<<"COPY"<<endl;}
//~Ship(){}

编译:

Ship(){}
Ship(const Ship & other){cout<<"COPY"<<endl;}
~Ship(){}

不编译:

Ship(){}
//Ship(const Ship & other){cout<<"COPY"<<endl;}
~Ship(){}

为什么插入用户定义的析构函数需要用户定义的复制构造函数,为什么我们在上面的例子中需要一个复制构造函数呢?

我希望上面的示例中不需要复制构造函数,因为甚至无法复制unique_ptr。

2 个答案:

答案 0 :(得分:11)

代码被编译,因为buildShip()将使用编译器在返回tmp时自动生成的移动构造函数。添加用户声明的析构函数可防止编译器自动生成析构函数。例如,请参阅thisthis个问题。并且由于成员upstd::unique_ptr,因此无法使用编译器生成的复制构造函数。并明确删除了unique_ptr的复制构造函数。

所以这将编译,因为显式要求编译器生成移动构造函数:

class Ship
{
public:
    Ship(){}
    Ship(Ship&&) = default;
    ~Ship(){}
    std::unique_ptr<container> up;
};

答案 1 :(得分:0)

这个想法是,如果编译器生成的析构函数对你的类不够好,那么复制构造函数和复制赋值运算符也可能不够好,所以编译器可能删除这些复制操作的隐式实现。从技术上讲,即使您有一个用户定义的析构函数,编译器仍然可以为您提供隐式复制操作,但在c ++ 11中不推荐使用该行为。

请参阅Rule of Three

AFAIK,你仍然需要一个复制构造函数,因为buildShip()按值返回。

(但是,有趣的是,您能够编译使用隐式复制构造函数的版本。由于unique_ptr成员,您不应该这样做。)