文章来源:http://blog.youkuaiyun.com/sxhelijian/article/details/23209967
浅复制和深复制
所谓浅复制,如同上面出现过的构造函数中处理的一样,直接为数据成员赋值即可。在很多情况下,这是可以的。创建新的对象,要为对象的数据成员分配存储空间,直接赋值就将值保存在相应的空间中。
然而,这种浅复制,却并不能通行天下,下面的程序中,浅复制带来了问题。
#include <iostream>
#include <cstring>
using namespace std;
class Test
{
private:
int a;
char *str;
public:
Test(int b, char *s)
{
a=b;
strcpy(str,s); //肇事地点,但不是祸端
}
Test(const Test& C)
{
a=C.a;
strcpy(str,C.str);
}
void show ()
{
cout<<a<<","<<str<<endl;
}
};
int main()
{
Test a(100,"hello");
Test b(a);
a.show();
b.show();
return 0;
}
程序运行中,会弹出一个窗口:程序的执行意外停止了。面对这个窗口,我们应该有感觉,这和使用指针不当有关系。
我们从main函数看起。
当程序执行到第28行Test a(100,"hello");时,对象a的数据成员a获得实际参数100的值,而数据成员str,即指针,是个随机地址值(指针的值,非指针指向的值)!在程序中,试图通过strcpy(str,s);将形式参数s指向的字符串"hello",复制到str所指向的那个位置,而那个位置,其地址并不是经过系统分配来的,这是个危险的操作。在这里,str这样未经过分配的地址(指针),被称为“野指针”。
在执行第29行Test b(a);时,同样的事情还要发生。
str这样的野指针是多么的霸道!在有的系统里,这样的行为是被接受的,可以想到其有多危险。有些系统中,不允许这样的事情发生的。于是,上面的程序在codeblock中调试会出错。这个错来的好。
解决这样的问题的方法,就是在构造函数中,要为指针类型的成员,分配专门的空间。以这条规则构建的复制,称作为深复制!
上面的程序,改写为:
#include <iostream>
#include <cstring>
using namespace std;
class Test
{
private:
int a;
char *str;
public:
Test(int b, char *s)
{
a=b;
str=new char[strlen(s)+1]; //分配str指向的空间,其长度根据s指向的字符串定。为何加1?字符串结束要用\0
strcpy(str,s); //前一程序的肇事地点,祸端已经由上一句摘除
}
Test(const Test& C)
{
a=C.a;
str=new char[strlen(C.str)+1]; //同上,这样str就不是野指针了
strcpy(str,C.str);
}
~Test()
{
delete []str;
}
void show ()
{
cout<<a<<","<<str<<endl;
}
};
int main()
{
Test a(100,"hello");
Test b(a);
a.show();
b.show();
return 0;
}