日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

对深拷贝与浅拷贝的再次理解

發布時間:2025/3/21 编程问答 10 豆豆
生活随笔 收集整理的這篇文章主要介紹了 对深拷贝与浅拷贝的再次理解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

對深拷貝與淺拷貝的再次理解

??? 記得11年底找工作的時候,面試時曾經遇到有面試官問的對深拷貝與淺拷貝的理解,那時候自己回來查了資料,寫了篇博客,感覺自己理解了,其實理解的不深刻,最近在調試bug的時候,再次遇到深拷貝與淺拷貝,認真分析了,寫寫自己的心得吧。

??? 先說下自己的理解吧,淺拷貝,即在定義一個類A,使用類似A?obj;??A?obj1(obj);或者A?obj1?=?obj;?時候,由于沒有自定義拷貝構造函數,C++編譯器自動會產生一個默認的拷貝構造函數。這個默認的拷貝構造函數采用的是“位拷貝”(淺拷貝),而非“值拷貝”(深拷貝)的方式,如果類中含有指針變量,默認的拷貝構造函數必定出錯。

用一句簡單的話來說就是淺拷貝,只是對指針的拷貝,拷貝后兩個指針指向同一個內存空間,深拷貝不但對指針進行拷貝,而且對指針指向的內容進行拷貝,經深拷貝后的指針是指向兩個不同地址的指針。

?

??? 淺拷貝會出現什么問題呢?

假如有一個成員變量的指針,char?*m_data;

其一,淺拷貝只是拷貝了指針,使得兩個指針指向同一個地址,這樣在對象塊結束,調用函數析構的時,會造成同一份資源析構2次,即delete同一塊內存2次,造成程序崩潰。

其二,淺拷貝使得obj.m_dataobj1.m_data指向同一塊內存,任何一方的變動都會影響到另一方。

其三,在釋放內存的時候,會造成obj1.m_data原有的內存沒有被釋放(這句話,剛開始我不太理解,如果沒有走自定義的拷貝構造函數,申請內存空間,A?obj1(obj);也不走默認構造函數,走的是默認的拷貝構造函數,何來分配空間直說,更不會造成obj1.m_data原有的內存沒有被釋放,這里剛開始我一直有疑問),造成內存泄露。

事實是這樣的,當delete?obj.m_data,?obj.m_data內存被釋放后,由于之前obj.m_dataobj1.m_data指向的是同一個內存空間,obj1.m_data所指的空間不能在被利用了,delete?obj1.m_data也不會成功,一致已經無法操作該空間,所以導致內存泄露。

??? 深拷貝采用了在堆內存中申請新的空間來存儲數據,這樣每個可以避免指針懸掛。

??? 下面來看看類string的拷貝構造函數

[cpp] view plain copy
  •   class?String??
  •   {??
  •   ????public:??
  •   ????????String(const?String?&other);????//拷貝構造函數??
  •   ????private:??
  •   ????????char?*m_data;???//用于保存字符串??
  •   };????
  •   ??
  •   String(const?String?&other)??
  •   {?????
  •   ????int?length?=?strlen(other.m_data);??
  •   ????m_data?=?new?char[length?+?1];??
  •   ????strcpy(m_data,?other.m_data);??
  • }???

  • ?

    ??? 可以看到在拷貝構造函數中為成員變量申請了新的內存空間,這就使得兩個對象的成員變量不指向同一個內存空間,除非你的確需要這樣做,用于實現一些其他的用途。

    ??? 淺拷貝:也就是在對象復制時,只是對對象中的數據成員進行簡單的賦值,如果對象中存在動態成員,即指針,淺拷貝就會出現問題,下面代碼:

    [cpp] view plain copy
  • #include?<stdio.h>??
  • ??
  • class?A??
  • {??
  • ????public:??
  • ????????A()??????//?構造函數,p指向堆中分配的一空間??
  • ????????{??
  • ????????????m_data?=?new?char(100);??
  • ????????????printf("默認構造函數\n");??
  • ????????}??
  • ????????~A()?????//?析構函數,釋放動態分配的空間??
  • ????????{??
  • ????????????if(m_data?!=?NULL)??
  • ????????????{??
  • ????????????????delete?m_data;??
  • ????????????????m_data?=?NULL;??
  • ????????????????printf("析構函數\n");??
  • ????????????}??
  • ????????}??
  • ????private:??
  • ????????char?*m_data;?????//?一指針成員??
  • };??
  • ??
  • int?main()??
  • {??
  • ????A?a;??
  • ????A?b(a);???//?復制對象??
  • ????return?0;??
  • }??
  • 運行結果:

    ***?glibc?detected?***?./simple:?double?free?or?corruption?(fasttop):?0x000000000c62a010?***

    分析:由于沒有拷貝構造函數,走編譯器默認的拷貝構造函數,A?b(a);?進行對象析構時,會造成釋放同一內存空間2次,導致內存泄露。

    ?

    ??? 深拷貝:對于深拷貝,針對成員變量存在指針的情況,不僅僅是簡單的指針賦值,而是重新分配內存空間,如下:

    [cpp] view plain copy
  • #include?<stdio.h>??
  • #include?<string>??
  • ??
  • class?A??
  • {??
  • ????public:??
  • ????????A()??????//?構造函數,p指向堆中分配的一空間??
  • ????????{??
  • ????????????m_pdata?=?new?char(100);??
  • ????????????printf("默認構造函數\n");??
  • ????????}??
  • ??
  • ????????A(const?A&?r)??
  • ????????{??
  • ????????????m_pdata?=?new?char(100);????//?為新對象重新動態分配空間??
  • ????????????memcpy(m_pdata,?r.m_pdata,?strlen(r.m_pdata));??
  • ????????????printf("copy構造函數\n");??
  • ????????}??
  • ??
  • ????????~A()?????//?析構函數,釋放動態分配的空間??
  • ????????{??
  • ????????????if(m_pdata?!=?NULL)??
  • ????????????{??
  • ????????????????delete?m_pdata;??
  • ????????????????printf("析構函數\n");??
  • ????????????}??
  • ????????}??
  • ??
  • ????private:??
  • ????????char?*m_pdata;?????//?一指針成員??
  • };??
  • ??
  • int?main()??
  • {??
  • ????A?a;??
  • ????A?b(a);???//?復制對象??
  • ????return?0;??
  • }??

  • ?

    ??? 下面是我在具體的應用中使用深拷貝的情況,現在把這個demo貼出來:

    [cpp] view plain copy
  • #include?<iostream>??
  • #include?<errno.h>??
  • #include?<vector>??
  • #include?<stdio.h>??
  • ??
  • using?namespace?std;??
  • ??
  • /*存儲記錄信息的結構體*/??
  • typedef?struct?_RECODER_VALUE_STRU??
  • {??
  • ????????int?Id;??
  • ????????int?Age;??
  • }RECODER_VALUE_STRU;??
  • ??
  • class?recorder??
  • {??
  • ????????public:??
  • ????????????????recorder()??
  • ????????????????{??
  • ????????????????????????m_stru_RecValue.Id?=?-1;??
  • ????????????????????????m_stru_RecValue.Age?=?-1;??
  • ????????????????????????m_pRecValue?=?&m_stru_RecValue;??
  • ??
  • ????????????????????????m_paddr?=?new?char[100];??
  • ????????????????????????memset(m_paddr,0x00?,100);??
  • ??
  • ????????????????????????printf("默認?construct?recorder->&m_stru_RecValue:?%x,\t?m_pRecValue:?%x\t?m_paddr:?%x\n",?&m_stru_RecValue,?m_pRecVa??
  • lue,?m_paddr);??
  • ????????????????}??
  • ??
  • ????????????????//拷貝構造函數??
  • /*??????????????recorder(const?recorder?&recorder)?
  • ????????????????{?
  • ????????????????????????m_stru_RecValue.Id?=?-1;????????
  • ????????????????????????m_stru_RecValue.Age?=?-1;?
  • ????????????????????????m_stru_RecValue?=?recorder.m_stru_RecValue;?
  • ????????????????????????m_pRecValue?=?&m_stru_RecValue;?
  • ?
  • ????????????????????????m_paddr?=?new?char[100];?
  • ????????????????????????memset(m_paddr,?0x00?,100);?
  • ????????????????????????memcpy(m_paddr,?recorder.m_paddr,?strlen(recorder.m_paddr));?
  • ?
  • ????????????????????????printf("拷貝?construct?recorder->&m_stru_RecValue:?%x\t?m_pRecValue:?%x\t?m_paddr:?%x\n",&m_stru_RecValue,?m_pRecValu?
  • e,?m_paddr);?
  • ????????????????}?
  • */??
  • ????????????????//構造函數??
  • ????????????????recorder(int?iId,?int?iAge)??
  • ????????????????{??
  • ????????????????????????m_stru_RecValue.Id?=?iId;??
  • ????????????????????????m_stru_RecValue.Age?=?iAge;??
  • ????????????????????????m_pRecValue?=?&m_stru_RecValue;??
  • ??
  • ????????????????????????m_paddr?=?new?char[100];??
  • ????????????????????????memset(m_paddr,?0x00?,100);??
  • ????????????????????????memcpy(m_paddr,?&iAge,?sizeof(int));??
  • ??
  • ????????????????????????printf("construct?recorder->&m_stru_RecValue:?%x?\t?m_pRecValue:?%x\t?m_paddr:?%x\n",?&m_stru_RecValue,?m_pRecValue,??
  • m_paddr);??
  • ????????????????}??
  • ??
  • ????????????????~recorder()??
  • ????????????????{??
  • ????????????????//??????cout<<"recorder?析構"<<endl;??
  • ????????????????????????/*if(m_paddr?!=?NULL)?
  • ????????????????????????{?
  • ????????????????????????????????delete?m_paddr;?
  • ????????????????????????????????m_paddr?=NULL;?
  • ????????????????????????}*/??
  • ????????????????}??
  • ??
  • ????????public:??
  • ????????????????RECODER_VALUE_STRU?m_stru_RecValue;//存儲記錄信息的結構體???
  • ????????????????void*?m_pRecValue;//每條記錄的值??
  • ????????????????char?*m_paddr;??
  • };??
  • ??
  • int?main()??
  • {??
  • ????????cout?<<"測試默認構造函數"<<endl<<endl;??
  • ????????recorder?btest;??
  • ????????recorder?btest1(btest);??
  • ??
  • ????????printf("非參:btest?->&m_stru_RecValue:?%x\t?addr:?%x\t?m_paddr:?%x\n",??&btest.m_stru_RecValue,?btest.m_pRecValue,??btest.m_paddr);??
  • ????????printf("非參:btest1->&m_stru_RecValue:?%x\t?addr:?%x\t?m_paddr:?%x\n",?&btest1.m_stru_RecValue,?btest1.m_pRecValue,?btest1.m_paddr);??
  • ??
  • ??
  • ????????cout?<<?endl<<"測試帶參數的構造函數"<<endl<<endl;??
  • ??
  • ??
  • ????????recorder?btest2(1,?100);??
  • ????????recorder?btest3(btest2);??
  • ????????printf("帶參:btest2->m_stru_RecValue:?%x\t?m_pRecValue:?%x\t,?m_paddr:?%x\n",?&btest2.m_stru_RecValue,?btest2.m_pRecValue,?btest2.m_??
  • paddr);??
  • ????????printf("帶參:btest3->m_stru_RecValue:?%x\t?m_pRecValue:?%x\t,?m_paddr:?%x\n",?&btest3.m_stru_RecValue,?btest3.m_pRecValue,?btest3.m_??
  • paddr);??
  • ??
  • ??
  • ????????return?0;??
  • }??
  • 對比結果:

    注釋掉自定義拷貝構造函數,運行結果:

    測試默認構造函數

    默認?construct?recorder->&m_stru_RecValue:?ddbb8de0,?????m_pRecValue:?ddbb8de0???m_paddr:?1b8a0010

    非參:btest?->&m_stru_RecValue:?ddbb8de0?????????addr:?ddbb8de0??m_paddr:?1b8a0010

    非參:btest1->&m_stru_RecValue:?ddbb8dc0?????????addr:?ddbb8de0??m_paddr:?1b8a0010

    測試帶參數的構造函數

    construct?recorder->&m_stru_RecValue:?ddbb8da0???m_pRecValue:?ddbb8da0???m_paddr:?1b8a0080

    帶參:btest2->m_stru_RecValue:?ddbb8da0??m_pRecValue:?ddbb8da0??,?m_paddr:?1b8a0080

    帶參:btest3->m_stru_RecValue:?ddbb8d80??m_pRecValue:?ddbb8da0??,?m_paddr:?1b8a0080

    默認拷貝構造函數結果分析:

    通過結果可以看出,當成員變量為指針變量的時候,指針成員變量指向的地址都是同一個地址,無論是申請空間的成員變量m_pRecValue,和僅僅作為指針賦值的成員變量m_paddr;結構體的地址是變化的,除了指針淺拷貝與深拷貝沒什么區別。

    打開自定義拷貝構造函數,運行結果:

    測試默認構造函數

    默認?construct?recorder->&m_stru_RecValue:?58bb9e20,?????m_pRecValue:?58bb9e20???m_paddr:?7a2c010

    拷貝?construct?recorder->&m_stru_RecValue:?58bb9e00??????m_pRecValue:?58bb9e00???m_paddr:?7a2c080

    非參:btest?->&m_stru_RecValue:?58bb9e20?????????addr:?58bb9e20??m_paddr:?7a2c010

    非參:btest1->&m_stru_RecValue:?58bb9e00?????????addr:?58bb9e00??m_paddr:?7a2c080

    測試帶參數的構造函數

    construct?recorder->&m_stru_RecValue:?58bb9de0???m_pRecValue:?58bb9de0???m_paddr:?7a2c0f0

    拷貝?construct?recorder->&m_stru_RecValue:?58bb9dc0??????m_pRecValue:?58bb9dc0???m_paddr:?7a2c160

    帶參:btest2->m_stru_RecValue:?58bb9de0??m_pRecValue:?58bb9de0??,?m_paddr:?7a2c0f0

    帶參:btest3->m_stru_RecValue:?58bb9dc0??m_pRecValue:?58bb9dc0??,?m_paddr:?7a2c160

    自定義深拷貝構造函數結果分析:

    從結果可以看出,所有成員變量的地址都不相同。

    其他:

    1.?有時候為了防止默認拷貝發生,可以聲明一個私有的拷貝構造函數(不用寫代碼),這樣的話,如果試圖調用?A? b(a);?就調用了私有的拷貝構造函數,編譯器會報錯,這也是一種偷懶的做法。

    2.??一個類中可以存在多個拷貝構造函數,例如:

    [cpp] view plain copy
  • Calss?A??
  • {??
  • Public:??
  • X(const?X&);//const拷貝構造??
  • X(X?&);//非const拷貝構造??
  • X(X&?,?int??iData);??
  • }??

  • ?

    暫時就先分析到這里,如果以后遇到新的關于拷貝構造的情況,會繼續分析。

    如是轉載,請指明原出處: http://blog.csdn.net/feitianxuxue,謝謝合作!

    總結

    以上是生活随笔為你收集整理的对深拷贝与浅拷贝的再次理解的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 精品久久久久久久久久久久久久久久久 | 黄色在线免费观看网站 | 免费人成年激情视频在线观看 | 久久在线视频精品 | 一级 黄 色 片69 | 婷婷五月色综合 | 那个网站可以看毛片 | 成人在线影片 | 国产精品一区电影 | 国产成人三级一区二区在线观看一 | 亚洲欧美一区二区视频 | 偷拍老头老太高潮抽搐 | 伊人网欧美 | 欧美综合自拍亚洲综合图片区 | 91国内视频 | 久久久久久久无码 | 日本欧美国产 | 男人操女人动漫 | 黑人无套内谢中国美女 | 国产av无码专区亚洲av毛片搜 | 日韩精品一卡 | 一本色道综合久久欧美日韩精品 | 精品三级在线观看 | 直接看的毛片 | 天天躁日日躁狠狠躁喷水 | 欧美日韩一区二区视频观看 | a亚洲精品| 91精品国产乱码久久久张津瑜 | 97成人免费视频 | 五月天中文字幕 | 国产主播一区二区 | 国产一区,二区 | 国产二区一区 | 黄色免费入口 | 成人自拍在线 | 欧美精品一区二区三 | 黄色精品视频在线观看 | 中文字幕xxxx | 欧美黄色a级大片 | 国产精品破处 | 国产良妇出轨视频在线观看 | 一区二区在线不卡 | 四虎影院在线看 | 97影院 | √天堂8资源中文在线 | 成年人深夜福利 | 午夜精品久久久 | av一区在线播放 | 久久久888 | 一区二区三区四区免费 | 人人干人人搞 | 超碰www| 日韩精品一区二区在线视频 | 中文字幕xxxx | 免费在线日韩 | 天天艹天天射 | 色老头网址 | 大肉大捧一进一出好爽视频 | 日本黄色不卡 | 美女一级黄 | 加勒比精品在线 | 久久人人精品 | 69xav | 2020亚洲男人天堂 | 天堂√| 美日韩一二三区 | 国产精品永久久久久久久久久 | 亚洲偷偷 | 日本黄色高清视频 | 捆绑凌虐一区二区三区 | 夜夜草导航| 337p粉嫩大胆色噜噜噜 | 中文字幕福利 | 哪里可以看毛片 | 久久成人小视频 | 婷婷综合久久 | 91成人小视频 | www.在线看| 黄色调教视频 | 国产爱搞 | 国产一区二区视频在线播放 | 日韩一道本 | 91精产国品一二三区在线观看 | 在线免费观看日韩 | 蜜桃精品视频在线 | 青青青免费视频观看在线 | 一本大道东京热无码aⅴ | 五月婷婷伊人网 | 人妻巨大乳一二三区 | 国产又黄又嫩又滑又白 | 青青草原国产 | 另类视频在线观看 | 国产免费久久精品国产传媒 | 日本黄色片在线播放 | www天天操| 韩漫动漫免费大全在线观看 | 天堂一区在线观看 | 亚洲国产97在线精品一区 | 国产免费网址 |