C++深拷贝与浅拷贝
浅拷贝
所谓浅拷贝,指的是在对象复制时,只对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝
class Rect
{
public:
Rect(){ count++; cout<<count<<endl; } //构造函数,计数器加1
//拷贝构造函数
/*Rect(const Rect &r)
*{
* width = r.width;
* height = r.height;
* count++;
*}
*/
~Rect(){ count--; cout<<count<<endl; } //析构函数,计数器减1
static int getCount(){ return count; } //返回计数器的值
//静态函数可以直接用类名访问
private:
int width;
int height;
static int count;
};
int Rect::count = 0; //初始化计数器
int main()
{
Rect rect1;
cout<<"The count of rect: "<<Rect::getCount()<<endl;
Rect rect2(rect1);
cout<<The count of rect: "<<Rect::getCount()<<endl;
}
//运行结果
1
The count of rect: 1
The count of rect: 1
0
-1
//这段代码对前面的类,加入了一个静态成员,目的是进行计数。在主函数中,首先创建对象rect1,输出此时的对象个数,然后使用rect1复制出对象rect2,再输出此时的对象个数,按照理解,此时应该有两个对象存在,但实际程序运行时,输出的都是1,反应出只有1个对象。此外,在销毁对象时,由于会调用销毁两个对象,类的析构函数会调用两次,此时的计数器将变为负数。
说白了,就是拷贝构造函数没有处理静态数据成员。
class Rect
{
public:
Rect(){p = new(100);}
~Rect(){
if(p!=NULL)
delete(p);
}
private:
int width;
int height;
int *p;
};
int main()
{
Rect rect1;
Rect rect2(rect1);
return 0;
}
//运行错误
在运行定义rect1对象后,由于在构造函数中有一个动态分配的语句,因此执行后的内存情况大致如下:

在使用rect1复制rect2时,由于执行的是浅拷贝,只是将成员的值进行赋值,这时 rect1.p= rect2.p,也即这两个指针指向了堆里的同一个空间,如下图所示:

在销毁对象时,两个对象的析构函数将对同一个内存空间释放两次,这就是错误出现的原因。我们需要的不是两个p有相同的值,而是两个p指向的空间有相同的值,解决办法就是使用“深拷贝”。
深拷贝
例子:
class Rect
{
public:
Rect(){p = new(100);}
Rect (const Rect &c)
{
width = c.width;
height = c.height;
p = new int;
*p = *(c.p);
}
~Rect(){
if(p!=NULL)
delete(p);
}
private:
int width;
int height;
int *p;
};
int main()
{
Rect rect1;
Rect rect2(rect1);
return 0;
}
此时,在完成对象的复制后,内存的一个大致情况如下:

此时rect1的p和rect2的p各自指向一段内存空间,但它们指向的空间具有相同的内容,这就是所谓的“深拷贝”。