直接看一个例子
// test.cpp
#include <iostream>
using namespace std;
class Test
{
public:
int m_num;
int *m_data;
Test(int num)
{
cout << "call constructor function..1 param.." << endl;
m_num = num;
m_data = new int[m_num];
}
~Test()
{
cout << "call destructor function.." << endl;
delete []m_data;
}
};
int main()
{
Test a(1);
Test b(a);
return 0;
}
// compile cmd
// g++ -g test.cpp -o test
运行该程序,会coredump,这是为什么呢?现在就引出浅拷贝的概念。
在对一个对象赋值给另一个对象的时候,如果只是进行数据成员间值的简单拷贝,即“浅拷贝”(默认拷贝构造函数干的事,关于默认拷贝构造函数可以参考点击我),比如上面这个例子,b.m_num=a.m_num; b.m_data=a.m_data;。注意,m_data可是个指针啊,那么此时,a.m_data和b.m_data就指向同一块内存区域。在程序结束时,a对象和b对象都会析构,a对象析构的时候,调用自定义析构函数会释放a.m_data指向的堆内存(代码中的delete操作),而当b对象析构的时候,又会执行一次delete操作,而且还是同一个地址(因为b.m_data=a.m_data),这就coredump掉了。
那应该如何修复上述问题呢?,现在就引出深拷贝的概念。
“深拷贝”指的是当拷贝对象中有对其他资源(如堆内存、文件、系统等)的引用时(这里的引用可以是指针* 或者 引用&),新对象要另开辟一块新的资源,而不再是对被拷贝对象中 对其他资源的引用(指针* 或者 引用&)进行单纯的赋值操作,然后同步拷贝开辟空间的值。
修复代码如下:
// test.cpp
#include <iostream>
#include <string.h>
using namespace std;
class Test
{
public:
int m_num;
int *m_data;
Test(int num)
{
cout << "call constructor function..1 param.." << endl;
m_num = num;
m_data = new int[m_num];
}
Test(const Test& obj)
{
cout << "call copy constructor function.." << endl;
m_num = obj.m_num; //浅拷贝
m_data = new int[m_num];
memcpy(m_data, obj.m_data, m_num); //自定义深拷贝
}
~Test()
{
cout << "call destructor function.." << endl;
delete []m_data;
}
};
int main()
{
Test a(1);
Test b(a);
return 0;
}
// compile cmd
// g++ -g test.cpp -o test
扩展延伸
现在考虑几个问题,
Q1、STL里的一些泛型算法,如copy,是深拷贝还是浅拷贝?
我们先看看copy的实现方式,可以查看http://www.cplusplus.com/reference/algorithm/copy/?kw=copy
所以STL的copy是深拷贝还是浅拷贝取决于class T的拷贝构造函数是怎么定义的。如果没有自定义拷贝构造函数,那么就是默认拷贝构造函数,就是浅拷贝;如果自定义了拷贝构造函数,那么看自定义拷贝构造函数里是怎么实现的,如果有深拷贝动作,那么STL的copy对class T就是深拷贝,如果只有浅拷贝动作,那么STL的copy对class T就是浅拷贝。(关于自定义拷贝构造函数和默认拷贝构造函数可以参考点击我)
Q2、STL里的一些泛型对比算法,如find,是浅对比还是深对比?
我们先看看find的实现方式,可以查看http://www.cplusplus.com/reference/algorithm/find/?kw=find
所以,find是深对比(两个对象是否完全一样,包含深拷贝的东西)还是浅对比(仅仅值比较),取决于class T对“==”操作符的重载函数,看这个重载函数是怎么判断的。