标题:深拷贝和浅拷贝


The default copy constructor performs: B

A. Deep copy

B. Shallow copy

C. Hard copy

D. Soft copy

⑴浅复制(浅克隆,Shallow copy

被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。

⑵深复制(深克隆,Deep copy

被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。

 

在构造函数中,如果含有动态内存分配(即用malloc()或者new分配的内存),那么必须声明自己的实现(重新分配一个内存,将被拷贝内存中的数据拷贝过来),不可采用默认的构造函数(默认的是实现位拷贝(浅拷贝),机械的将拷贝对象中的指针指向被拷贝对象的内存)。假如不实现自己的拷贝函数,那么在传值调用的时候,它会产生问题。看看下面的例子:

 

void DoNothing(String localstring)

{

}

 

String s = "Hello, my house!";

 

DoNothing(s);

 

上面的代码看起来好象没有问题,但假如String类没有自己实现构造函数,那么就会出问题。因为被传递的参数localstring是一个值传递,如下图所示,它必须从s通过(缺省)拷贝构造函数进行初始化。由于String类没有自己实现一个拷贝构造函数,默认的拷贝构造函数将被调用。于是localstring拥有了一个s内的指针的拷贝(即localstring这个拷贝对象同样指向了s的内存部分)。当DoNothing()结束运行时,localstring离开了其生存空间,调用析构函数。其结果也将是:s包含一个指向localstring早已删除的内存的指针。


在结构体中,同样存在深拷贝和浅拷贝问题。结构体中如果定义了指针,那么在拷贝(使用=运算符)的时候,也只是将指针的地址拷贝到目标中。

 加入结构体中,只包含了普通的类型(非指针),那么下面的代码是正确的:

typdef struct _struct1

{

       int a;

       char b;

}struct1;

struct1 s1 = {1, ‘a’};

struct1 s2 = s1;//可以


但是,当结构体中包含了指针,问题就来了:

typdef struct _struct2

{

       int a;

       char *p;

}struct2;

struct2 s1;

s1.a = 10;

s1.p = (char *)malloc(100);

struct2 s2 = s1;//这是一个浅拷贝,此时s1.p和s2.p指向了同一块内存,一旦将s1.p释放了,s2.p就是一个野指针了

free(s1.p);

s2.p=?野指针

 

深拷贝需要程序员自己实现:

 

struct2 s1;

s1.a = 10;

s1.p = (char *)malloc(100);

struct2 s2;

s2.a=s1.a;

s2.p=(char *)malloc(100);

memcpy(s2.p,s1.p,100);

free(s1.p);

即使将s1.p释放了,s2.p此时也不是野指针了,依然有效



看文字不过瘾?点击我,进入周哥教IT视频教学
麦洛科菲长期致力于IT安全技术的推广与普及,我们更专业!我们的学员已经广泛就职于BAT360等各大IT互联网公司。详情请参考我们的 业界反馈 《周哥教IT.C语言深学活用》视频

我们的微信公众号,敬请关注