关于C++默认拷贝构造函数产生的问题的讨论
對于拷貝構造函數,我前面的博文有提起過,不過,有的時候,淺拷貝和深拷貝真的很難理解,所以,我們再進行關于拷貝構造函數的一些討論。
大家都整到拷貝構造函數分為淺拷貝和深拷貝,系統默認的拷貝構造函數是淺拷貝。
默認拷貝構造函數以內存拷貝的方式將舊有對象的內存空間拷貝到新對象的內存空間。
如果類中有指針類型的類型的時候,默認拷貝構造函數只能復制指針屬性的值,而不能復制指針屬性所指向的內存,此時,如果我們自己不顯式定義拷貝構造函數,那么我們在編程的時候,可能會出現很詭異的問題。
顯式定義拷貝構造函數來完成指針屬性等需要特殊處理的屬性的拷貝工作。
The Number one : ?我們先來看淺拷貝帶來的問題
---------------------我是分割線------------------------
#?include?<iostream> using?namespace?std;class?Car { private:char*??brand;float??price; public:Car(const?char*?sz,?float?p)???????{//構造函數中為brand分配內存brand?=?new?char[strlen(sz)+1];strcpy(brand,?sz);}~Car{//析構函數中釋放申請的內存delete[]?brand;cout?<<?"?Clear?is?over?!?"?<<?endl;????????}void?just_print(){cout?<<?"brand?:?"?<<?brand?<<?endl;cout?<<?"price?:?"?<<?price?<<?endl;} };int?main(void) {Car?car_one("BMW",120);car_one.just_print();//調用默認的拷貝構造函數Car?car_two(comp_one);car_two.print();return?0; }----------------------------------------------------------------------------
這個程序運行失敗,代碼分析:
1、car_two(car_one)等價于
? ? ? ? ?car_two.brand = car_one.brand;
? ? ? ? ?car_two.price ?= car_one.price;
2、經過賦值操作后,兩個對象中的指針指向的是同一塊動態內存,當car_one和car_two撤銷時,其釋放函數都要釋放同一塊動態內存內存,可是,兩個對象撤銷有先有后,一旦一個對象被撤銷,另一個對象的brand指針變速"野指針",使用該指針再次釋放同一塊動態內存會引發內存錯誤。
不僅僅是重復釋放內存的問題,還會出現其他問題:
-------------------------------------------------------------------------------
int?main(void) {Car?car_one("Dell",?7000);if(true){car?car_two(car_one);car_two.print();}//car_one.brand指向的動態內存此時已經被釋放car_one.print();return?0; }-------------------------------------------------------------------------------------------
由于car_two是在if結構中定義的局部對象,因此if結構退出時,car_two被撤銷,系統自動調用其析構函數,釋放了car_two.brand所指向的動態內存,由于car_one和car_two值相同,此時car_one.brand已無所指,成了野指針,此時,對該指針的讀寫操作都會引發無法預料的錯誤。
----------------------------------------------------------------------------
此時,我們就需要自己來定義拷貝構造函數:
----------------------------------------------------------------------------
//顯式定義構造函數 #?include?<iostream> #?include?<cstring> using?namespace?std;class?Car { private:char*????brand;float????price; public:Car(const?char*??sz,?float??p)????{brand?=?new?char[strlen(sz)+1];strcpy(brand,?sz);price?=?p;????????}//自定義拷貝構造函數Car(const??Car&??cp){//重新為brand開辟與cp.brand同等大小的內存空間brand?=?new?char[strlen(cp.brand)?+?1];//strcpy(brand,?cp.brand);price?=?cp.price;????????}~Car(){delete[]??brand;cout?<<?"clear?over?"?<<endl; ?}void?print(){cout?<<?"brand?"?<<?endl;cout?<<?"price?"?<<?endl;?}???? };int?main(void) {Car?car_one("Dell",?8999);car_one.print();//Car?car_two(car_one);car_two.print();//沒有采用brand?=?cp.brand?這種直接直接賦值,而是重新申請動態內存,使用//庫函數strcpy實現了字符串的復制//car_one.brand和car_two.brand指向兩塊不同的內存,避免了錯誤return?0; }------------------------------------------------------------------------------------------
最后提一點,自定義的拷貝構造函數,最好也重載operator=運算符!
-----------------------------------------------------------------------------------------
轉載于:https://blog.51cto.com/liam2199/1417892
總結
以上是生活随笔為你收集整理的关于C++默认拷贝构造函数产生的问题的讨论的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《游戏实战数据分析》读书笔记
- 下一篇: MySQL学习笔记_6_SQL语言的设计