深拷贝与浅拷贝
前面说到了拷贝构造函数,但是情况并未列举完。我怕文章太长就分开写,看的舒服。
有一种情况,那就是当构造函数中有指针操作,怎么办?
#include <iostream>
using namespace std;
class A{
private:
int *a;
public:
A(){
a = new int[100];
cout<<"构造函数"<<endl;
}
~A(){
delete a;
cout<<"析构函数"<<endl;
}
};
int main(){
A a;
A b = a;
return 0;
}
看起来没有错,但是会在运行时报错:
翻译一下,testSTACK是我工程的名字,被释放的指针没有被分配,也就是说析构函数释放了一个空指针!
怎么会呢?
这就涉及到一个知识点,就是堆栈关系:堆栈关系
如果嫌文章太长,那我就简单说一下。new出来的对象和指针不存放在同一片内存中,他们是指向关系。
当我们第一次使用析构函数释放掉pointer1的时候,pointer1指向的堆空间new int[100]被释放,到这一步一切顺利。
但是这时候pointer2其实已经指空了!再对pointer2进行释放,会报错。
就像一个软件,存在路径a上,现在创建一个快捷方式,放在桌面,路径为b,当a删除,b自然找不到源文件。
简单的说,这种只拷贝了指针但是没有拷贝指针指向的地址空间的拷贝,叫做浅拷贝。
可是在一些时候,这样做会出错,我们怎么解决这样的错误?利用深拷贝。
什么是深拷贝,就是连同地址空间一起拷贝。
这样释放的时候便不会出错。
#include <iostream>
using namespace std;
class A{
private:
int *a;
public:
A(){
a = new int;
cout<<"构造函数"<<endl;
}
A(const A& b){
a = new int[100];
*a = *(b.a);
cout<<"拷贝构造函数"<<endl;
}
~A(){
delete a;
cout<<"析构函数"<<endl;
}
};
int main(){
A a;
A b = a;
return 0;
}
在执行 A b = a 的时候,编译器调用拷贝构造函数。为对象b中的私有成员a申请了一片空间之后,让指针a指向这篇空间。这片空间被赋值为与参数中的空间相同,所以不会出现浅拷贝的情况。
问:拷贝构造函数为什么需要用引用传递,而不用值传递?
答:若是值传递,那么每次声明参数的时候都会再找值赋给当前声明的参数,这样一来就会进行无限递归的死循环。而引用传递利用地址,直接确定了拷贝对象的地址,不会造成无限递归。