關(guān)于C++默認(rèn)拷貝構(gòu)造函數(shù)產(chǎn)生的問題的討論
對于拷貝構(gòu)造函數(shù),我前面的博文有提起過,不過,有的時(shí)候,淺拷貝和深拷貝真的很難理解,所以,我們再進(jìn)行關(guān)于拷貝構(gòu)造函數(shù)的一些討論。
大家都整到拷貝構(gòu)造函數(shù)分為淺拷貝和深拷貝,系統(tǒng)默認(rèn)的拷貝構(gòu)造函數(shù)是淺拷貝。
默認(rèn)拷貝構(gòu)造函數(shù)以內(nèi)存拷貝的方式將舊有對象的內(nèi)存空間拷貝到新對象的內(nèi)存空間。
如果類中有指針類型的類型的時(shí)候,默認(rèn)拷貝構(gòu)造函數(shù)只能復(fù)制指針屬性的值,而不能復(fù)制指針屬性所指向的內(nèi)存,此時(shí),如果我們自己不顯式定義拷貝構(gòu)造函數(shù),那么我們在編程的時(shí)候,可能會出現(xiàn)很詭異的問題。
顯式定義拷貝構(gòu)造函數(shù)來完成指針屬性等需要特殊處理的屬性的拷貝工作。
The Number one : 我們先來看淺拷貝帶來的問題
---------------------我是分割線------------------------
- # include <iostream>
- using namespace std;
- class Car
- {
- private:
- char* brand;
- float price;
- public:
- Car(const char* sz, float p)
- {
- //構(gòu)造函數(shù)中為brand分配內(nèi)存
- brand = new char[strlen(sz)+1];
- strcpy(brand, sz);
- }
- ~Car
- {
- //析構(gòu)函數(shù)中釋放申請的內(nèi)存
- 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();
- //調(diào)用默認(rèn)的拷貝構(gòu)造函數(shù)
- Car car_two(comp_one);
- car_two.print();
- return 0;
- }
----------------------------------------------------------------------------
這個(gè)程序運(yùn)行失敗,代碼分析:
1、car_two(car_one)等價(jià)于
car_two.brand = car_one.brand;
car_two.price = car_one.price;
2、經(jīng)過賦值操作后,兩個(gè)對象中的指針指向的是同一塊動態(tài)內(nèi)存,當(dāng)car_one和car_two撤銷時(shí),其釋放函數(shù)都要釋放同一塊動態(tài)內(nèi)存內(nèi)存,可是,兩個(gè)對象撤銷有先有后,一旦一個(gè)對象被撤銷,另一個(gè)對象的brand指針變速"野指針",使用該指針再次釋放同一塊動態(tài)內(nèi)存會引發(fā)內(nèi)存錯(cuò)誤。
不僅僅是重復(fù)釋放內(nèi)存的問題,還會出現(xiàn)其他問題:
-------------------------------------------------------------------------------
- int main(void)
- {
- Car car_one("Dell", 7000);
- if(true)
- {
- car car_two(car_one);
- car_two.print();
- }
- //car_one.brand指向的動態(tài)內(nèi)存此時(shí)已經(jīng)被釋放
- car_one.print();
- return 0;
- }
-------------------------------------------------------------------------------------------
由于car_two是在if結(jié)構(gòu)中定義的局部對象,因此if結(jié)構(gòu)退出時(shí),car_two被撤銷,系統(tǒng)自動調(diào)用其析構(gòu)函數(shù),釋放了car_two.brand所指向的動態(tài)內(nèi)存,由于car_one和car_two值相同,此時(shí)car_one.brand已無所指,成了野指針,此時(shí),對該指針的讀寫操作都會引發(fā)無法預(yù)料的錯(cuò)誤。
----------------------------------------------------------------------------
此時(shí),我們就需要自己來定義拷貝構(gòu)造函數(shù):
----------------------------------------------------------------------------
- //顯式定義構(gòu)造函數(shù)
- # 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;
- }
- //自定義拷貝構(gòu)造函數(shù)
- Car(const Car& cp)
- {
- //重新為brand開辟與cp.brand同等大小的內(nèi)存空間
- 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 這種直接直接賦值,而是重新申請動態(tài)內(nèi)存,使用
- //庫函數(shù)strcpy實(shí)現(xiàn)了字符串的復(fù)制
- //car_one.brand和car_two.brand指向兩塊不同的內(nèi)存,避免了錯(cuò)誤
- return 0;
- }
------------------------------------------------------------------------------------------
***提一點(diǎn),自定義的拷貝構(gòu)造函數(shù),***也重載operator=運(yùn)算符!
-----------------------------------------------------------------------------------------