【C++】浅拷贝和深拷贝

【C++】浅拷贝和深拷贝深拷贝与浅拷贝简单的来说,【浅拷贝】是增加了一个指针,指向原来已经存在的内存。而【深拷贝】是增加了一个指针,并新开辟了一块空间让指针指向这块新开辟的空间。【浅拷贝】在多个对象指向一块空间的时候,释放一个空间会导致其他对象所使用的空间也被释放了,再次释放便会出现错误浅拷贝为了形象化说明什么是深拷贝和浅拷贝,我们就先写一个String类类里面包含【构造函数】,【拷贝构造函数】,【赋值运算符重载】,以及…

深拷贝与浅拷贝

简单的来说,【浅拷贝】是增加了一个指针,指向原来已经存在的内存。而【深拷贝】是增加了一个指针,并新开辟了一块空间

让指针指向这块新开辟的空间。

【浅拷贝】在多个对象指向一块空间的时候,释放一个空间会导致其他对象所使用的空间也被释放了,再次释放便会出现错误

浅拷贝

为了形象化说明什么是深拷贝和浅拷贝,我们就先写一个String类

类里面包含【构造函数】【拷贝构造函数】【赋值运算符重载】,以及【析构函数】【输出操作符“<<”的重载】

[cpp] 
view plain
 copy

  1. class String  
  2. {  
  3. public:  
  4.     String(const char *pStr = “”)  
  5.     {  
  6.         if(NULL == pStr)  
  7.         {  
  8.             pstr = new char[1];  
  9.             *pstr = ‘\0’;  
  10.         }  
  11.         else  
  12.         {  
  13.             pstr = new char[strlen(pStr)+1];//加1,某位是’\0′  
  14.             strcpy(pstr,pStr);//用拷贝字符串的函数   
  15.         }  
  16.     }  
  17.       
  18.     String(const String &s)  
  19.         :pstr(s.pstr)//浅拷贝的问题,指向同一块空间,可能造成释放的错误 ,这是浅拷贝的缺点   
  20.     {}  
  21.       
  22.     String& operator=(const String&s)  
  23.     {  
  24.         if(this != &s)  
  25.         {  
  26.             delete[] pstr;//将原来所指向的空间释放   
  27.             pstr = s.pstr;//让pstr重新指向s的pstr所指向的空间(也会导致错误)   
  28.         }   
  29.         return *this;  
  30.     }  
  31.       
  32.     ~String()  
  33.     {  
  34.         if(NULL != pstr)  
  35.         {  
  36.             delete[] pstr;//释放指针所指向的内容   
  37.             pstr = NULL;//将指针置为空      
  38.         }   
  39.     }   
  40.     friend ostream&operator<<(ostream & _cout,const String &s)  
  41.     {  
  42.         _cout<<s.pstr;  
  43.         return _cout;  
  44.     }  
  45. private:  
  46.     char *pstr;       
  47. };  

经过测试之后,在某种情况下是可以正常运行的,在特定情况下是不可以正常的运行的

举一个不能正常运行的例子

[cpp] 
view plain
 copy

  1. int main()  
  2. {     
  3.     String s1(“sss”);  
  4.     String s2(s1);  
  5.     String s3(NULL);  
  6.     s3 = s1;  
  7.     cout<<s1<<endl;  
  8.     cout<<s2<<endl;  
  9.     cout<<s3<<endl;  
  10.     return 0;  
  11. }  

在该例子中,我们有三个String类的对象,s1调用
【构造函数】
存入字符”sss”

s2调用【拷贝构造函数】来利用s1进行初始化,s3则用【赋值运算符】来进行初始化

黑框框里输出了三个“sss”

然而!

【C++】浅拷贝和深拷贝

这是为什么呢?

【C++】浅拷贝和深拷贝

通过监视,我们发现他们指向的都是同一块空间,因为地址都是【0x01044570】

在让我们看看【析构函数】

[cpp] 
view plain
 copy

  1. ~String()  
  2. {  
  3.     if (pstr != NULL)  
  4.     {  
  5.         delete[] pstr;  
  6.         pstr = NULL;  
  7.     }  
  8. }  

当我们释放s3的时候,可以正常释放

然而当释放s2的时候,由于【s3已经释放过了】,所以s2所指向的这段空间已经不属于s1或者s2了

此时我们调用delete释放的时候,必然会崩溃(毕竟人家本来就不属于你呀)

【C++】浅拷贝和深拷贝

深拷贝

深拷贝以及深浅拷贝的对比

深拷贝和浅拷贝的不同之处,仅仅在于修改了下【拷贝构造函数】,以及【赋值运算符的重载】

[cpp] 
view plain
 copy

  1. String(const String &s)  
  2.     :pstr(new char[strlen(s.pstr)+1])  
  3. {  
  4.     strcpy(pstr,s.pstr);   
  5. }  
  6.   
  7. String& operator=(const String &s)  
  8. {  
  9.     if(this != &s)  
  10.     {  
  11.         char* tmp = new char[strlen(s.pstr)+1];//动态开辟一个临时变量,然后将pstr指向这一个新的临时变量里  
  12.         delete[] pstr;//将原来的空间进行释放  
  13.         strcpy(tmp,s.pstr);//将s.pstr里的内容复制到临时变量中  
  14.         pstr = tmp;//pstr指向临时变量的这段空间  
  15.     }  
  16.     return *this;  
  17. }  

对比一下浅拷贝的【拷贝构造函数】【赋值运算符重载】

[cpp] 
view plain
 copy

  1. String(const String &s)  
  2.     :pstr(s.pstr)//浅拷贝的问题,指向同一块空间,可能造成释放的错误 ,这是浅拷贝的缺点   
  3. {}  
  4.   
  5. String& operator=(const String&s)  
  6. {  
  7.     if(this != &s)  
  8.     {  
  9.         delete[] pstr;//将原来所指向的空间释放   
  10.         pstr = s.pstr;//让pstr重新指向s的pstr所指向的空间(也会导致错误)   
  11.     }   
  12.     return *this;  
  13. }  

【C++】浅拷贝和深拷贝

深拷贝完整版

[cpp] 
view plain
 copy

  1. class String  
  2. {  
  3. public:  
  4.     String(const char* pStr = “”)  
  5.     {     
  6.         cout<<“String()”<<endl;  
  7.         if(NULL == pStr)  
  8.         {  
  9.             pstr = new char[1];  
  10.             *pstr = ‘\0’;  
  11.         }  
  12.         else  
  13.         {  
  14.             pstr = new char[strlen(pStr)+1];  
  15.             strcpy(pstr,pStr);   
  16.         }  
  17.     }  
  18.     String(const String &s)  
  19.         :pstr(new char[strlen(s.pstr)+1])  
  20.     {  
  21.         strcpy(pstr,s.pstr);   
  22.     }  
  23.       
  24.     String& operator=(const String &s)  
  25.     {  
  26.         if(this != &s)  
  27.         {  
  28.             char* tmp = new char[strlen(s.pstr)+1];//pstr;  
  29.             delete[] pstr;  
  30.             strcpy(tmp,s.pstr);  
  31.             pstr = tmp;  
  32.         }  
  33.         return *this;  
  34.     }  
  35.       
  36.     ~String()  
  37.     {  
  38.         if(NULL != pstr)  
  39.         {  
  40.             delete[] pstr;  
  41.             pstr = NULL;      
  42.         }  
  43.     }     
  44. private:  
  45.     char *pstr;  
  46. };  

除此之外,我们可以简化一下深拷贝的【拷贝构造函数】【赋值运算符重载】

[cpp] 
view plain
 copy

  1. <span style=“color:#000000;”>String(const String& s)  
  2. :_ptr(NULL)  
  3. {  
  4.     String temp(s._ptr);  
  5.     std::swap(_ptr, temp._ptr);  
  6. }  
  7. </span>  

【拷贝构造函数】里用s定义临时变量,临时变量会自动调用构造函数开辟空间

然后用swap这个函数交换两个变量之间的内容

原来的内容在temp,并且出了【拷贝构造函数】就销毁了,避免了内存泄漏

[cpp] 
view plain
 copy

  1. String& operator=(const String& s)  
  2. {  
  3.     if (this != &s)  
  4.     {  
  5.         String temp(s);  
  6.         swap(_ptr, temp._ptr);  
  7.     }  
  8.     return *this;  
  9. }  
[cpp] 
view plain
 copy

  1. String& operator=(const String& s)  
  2. {  
  3.     if(this != &s)  
  4.     {  
  5.         String temp(s._ptr);  
  6.         swap(_ptr,temp._ptr);  
  7.     }  
  8.     return *this;  
  9. }  
[cpp] 
view plain
 copy

  1. String& operator=(String temp)  
  2. {  
  3.     swap(_ptr,temp._ptr);  
  4.     return *this;  
  5. }  


【赋值运算符重载】
里,也可以用到类似的方法。在第三个方法里,直接传入一个临时变量,连if判断都可以省去了



总结

【浅拷贝】只是增加了一个指针,指向已存在对象的内存。

【深拷贝】是增加了一个指针,并新开辟了一块空间,让指针指向这块新开辟的空间。

【浅拷贝】在多个对象指向一块空间的时候,释放一个空间会导致其他对象所使用的空间也被释放了,再次释放便会出现错误

今天的文章【C++】浅拷贝和深拷贝分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/25398.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注