举个例子来说吧
这是个浅拷贝的例子
#include <iostream>
#include <cstring>
using namespace std;
class TString
{
public:
TString(char *ap = "china");
TString(const TString &r);
~TString();
void display()const;
private:
char *m_pstr;
};
TString::TString(char *ap)
{
if (ap)
{
m_pstr = new char[strlen(ap)+1];
strcpy(m_pstr, ap);
}
else
m_pstr = 0;
}
TString::TString(const TString &r)
{
m_pstr = r.m_pstr;
} //人为实现默认拷贝构造函数
void TString::display()const
{
cout << m_pstr << endl;
}
TString::~TString()
{
delete []m_pstr;
}
int main()
{
TString str1("japan");
str1.display();
TString str2;
str2.display();
TString str3(str2);
str3.display();
return 0;
}
这样程序在编译时无错误也无警告,但在执行后会出错 “Debug Assertion Failed”, 中断执行。因为在执行 TString str3(str2);语句时,系统调用默认拷贝构造函数,负责将对象str1的数据成员m_pstr中存放的地址赋值给str2中的m_pstr.如下图所示:
这样在执行display()的时候看不出问题,但是,当对象生命周期结束需要撤销对象时,首先由str3对象调用析构函数,将str3.m_pstr所指向的字符串china所在的动态内存空间释放,此时内存状态如图。这样在str2调用析构函数之前,m_pstr成了悬挂指针。因此str2无法正确执行析构函数代码delete []m_pstr,从而容易导致出错。
把上边的系统默认构造函数改一下,就变成了深拷贝。
//定义拷贝构造函数
TString::TString(const TString &r)
{
if (r.m_pstr)
{
m_pstr = new char[strlen(r.m_pstr)+1];
strcpy(m_pstr, r.m_pstr);
}
else
m_pstr = 0;
}
这样在执行 TString str3(str2)时,如右图所示这样就不会有悬挂指针的问题出现了。
这就是深拷贝。