今天来探讨一下,假设类中有内存的申请和释放.那么我们的拷贝构造函数会怎么样了.

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
using namespace std;
class Tool
{
};
class Dog
{
public:
Dog()
{
cout<<"Dog::Dog()"<<endl;
}
Dog (const Dog& dog)
{
}
~Dog()
{
cout<<"Dog::~Dog()"<<endl;
delete dog_tool_;
}
Tool *dog_tool_=new Tool();
};
int main() {
Dog dog1;
Dog dog2(dog1);
cout<<dog1.dog_tool_<<endl;
cout<<dog2.dog_tool_<<endl;
return 0;
}

Error

1
double free or corruption (fasttop): 0x0000000001fc2010 ***

输出结果:

1
2
3
4
5
6
Dog::Dog()
0x1fc2010
0x1fc2010
Dog::~Dog()
Dog::~Dog()
Error:double free or corruption (fasttop): 0x0000000001fc2010 ***

错误提示:两次释放同一块空间

Analysis

看到这个错误提示,以及输出的两个相同地址,可以肯定这个错误是由于析构函数两次释放同一块内存导致的. 解决方案很简单,只有在Dog类中显示的写出拷贝构造函数即可(其实初始列表不写也是可以的)

1
2
3
4
Dog (const Dog& dog):dog_tool_(new Tool())
{
}

这样我们有如下的输出

1
2
3
4
5
Dog::Dog()
0x1195010
0x1195030
Dog::~Dog()
Dog::~Dog()

很显然,地址不一样了,那么再析构的时候就不会出现两次删除同一块地址.

Summary

很多人把这种做法叫深拷贝,对应之前的隐式拷贝构造叫浅拷贝