以下代码编译:
#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。
答案 0 :(得分:11)
代码被编译,因为buildShip()
将使用编译器在返回tmp
时自动生成的移动构造函数。添加用户声明的析构函数可防止编译器自动生成析构函数。例如,请参阅this或this个问题。并且由于成员up
是std::unique_ptr
,因此无法使用编译器生成的复制构造函数。并明确删除了unique_ptr
的复制构造函数。
所以这将编译,因为显式要求编译器生成移动构造函数:
class Ship
{
public:
Ship(){}
Ship(Ship&&) = default;
~Ship(){}
std::unique_ptr<container> up;
};
答案 1 :(得分:0)
这个想法是,如果编译器生成的析构函数对你的类不够好,那么复制构造函数和复制赋值运算符也可能不够好,所以编译器可能删除这些复制操作的隐式实现。从技术上讲,即使您有一个用户定义的析构函数,编译器仍然可以为您提供隐式复制操作,但在c ++ 11中不推荐使用该行为。
AFAIK,你仍然需要一个复制构造函数,因为buildShip()
按值返回。
(但是,有趣的是,您能够编译使用隐式复制构造函数的版本。由于unique_ptr
成员,您不应该这样做。)