浅拷贝和深拷贝
1、什么叫浅拷贝?什么叫深拷贝?
同类对象之间相互赋值,并且赋值运算符没有经过重载的话,赋值的结果就是使得等号左边变量内存空间中的每一个字节都和右边的一样。这样的赋值叫做浅拷贝。
但是有时候我们所要的两个对象相等,并不是指两个对象的内存空间中每个字节都相等。例如:假如s1和s2为两个指针,指向两块不同的内存空间。我们想要的效果通过执行s1=s2,使得是s1和s2指向两块不同的内存空间,并且将s2内存空间中的内容复制一份到s1内存空间中。我们的这种需求需要使用深拷贝实现。
s1和s2分别是两个指向不同字符串的指针:
此时直接执行下述语句:
s1=s2;
导致的结果是:
这并不是我们想要达到的效果。并且这样的操作可能导致以下几个问题:
- 如果S1对象消亡,析构函数将释放 S1.str指向的空间,则S2消亡时还要释放一次,不妥。
- 如果执行 S1 = “other”;会导致S2.str指向的地方被delete
这个时候我们就需要对赋值运算符进行重载以达到我们想要的效果。
2、需要考虑浅拷贝深拷贝问题的场景有哪些?
需要用到深拷贝的场景有下述两个,上面的例子属于场景二。
(1)初始化语句:使用一个对象初始化另外一个对象的初始化语句。
(2)赋值语句:相同类型的对象之间相互赋值的语句。
3、如何实现深拷贝?需要考虑哪几个点?
(1)对于第一个场景:需要写复制构造函数:
string s2 = "hehe";
string s1 = s2;//场景一
写复制构造函数需要考虑的问题:
- 需要先创建一块动态内存,并且让str指向这块动态内存
- 将传入对象的内容复制一份到这块动态内存(利用成员函数内可以直接访问同类型对象的数据这一特性)
String( String & s)
{
str = new char[strlen(s.str)+1];
strcpy(str,s.str);//s.str可以直接访问同类型对象的数据
}
(2)对于第二个场景:需要写赋值运算符重载函数:
String s1 = "hehe";
String s2 = "dada"
s1=s2;//场景二
写赋值运算符重载函数需要考虑的问题:
- 问题一:假如s1和s2指向的是同一个对象,直接返回
- 问题二:假如s1原本指向了一块动态内存,先将这块内存释放
- 问题三:假如s2本身就指向空,直接让s1指向空,不需要再调用字符串拷贝函数
String & operator = (const String & s){
if( this == & s) //解决问题一
return * this;
if(str) //解决问题二
delete [] str;
if(s.str){ //解决问题三
str = new char[strlen(s.str)+1];
strcpy( str,s.str);
}else{
str=NULL;
}
return * this;
}
//上述代码兼顾到了实现需求,以及实现效率问题