//類的深拷貝和淺拷貝 #define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; class Point{ public: Point(int _a,int _b,const char *pin/*in*/){ x = _a; y = _b; remark = (char *)malloc(sizeof(char)*(strlen(pin) + 1)); strcpy(remark, pin); cout << "我是自定義的有參構造函數4" << endl; } Point(Point &pm){ cout << "我是自定義的拷貝構造函數3" << endl; //修改拷貝構造函數 x = pm.x; y = pm.y; //remark = pm.remark; 這句話錯誤 //修改后的方案 remark = (char *)malloc(sizeof(char)*(strlen(pm.remark) + 1)); strcpy(remark, pm.remark); } ~Point(){ if (remark!=NULL) { free(remark); } cout << "我是自定義的析構函數2" << endl; } void GetPremark(){ printf("指針變量remark的地址是%x\n", remark); } //BBB---運算符重載 void operator=(Point &pm){ //CCC 解決方案第三步 if (remark!=NULL) { free(remark); remark = NULL; } //解決方案改良第二步(以下) x = pm.x; y = pm.y; remark = (char *)malloc(sizeof(char)*(strlen(pm.remark) + 1)); strcpy(remark, pm.remark); } private: int x; int y; char *remark; }; void ProtectA(){ Point p1(1, 1, "123"); Point p2 = p1; printf("這是p1中字符指針的地址\n"); p1.GetPremark();//打印 ad95e8 printf("這是p2中字符指針的地址\n"); p2.GetPremark();//打印 ad95e8 //這說明類對象之間拷貝指針拷貝了指針變量的值(兩個指針指向同一片內存),並沒有新分配內存 //出現問題:當先調用p2(函數的壓棧,先定義后釋放)的析構函數的時候,會釋放指針變量remark指向的內存, //當調用p1的析構函數的時候就會報錯 //解決方案第一步--修改類的拷貝構造函數 //BUG事例 //Point p3;//報錯 error C2512: “Point”: 沒有合適的默認構造函數可用 //這說明只要定義了有參構造函數,那么c++編譯器就不會自動創建無參構造函數 Point p4(2,3,"456"); //賦值操作 //p4 = p2; //分析:賦值操作會將p2的所有值(包括指針變量的值)拷貝到p4對象中 //此時又會出現兩個指針變量指向同一片內存的情況,當析構對象p4的時候,會釋放指針變量指向的內存 //那么析構p2的時候又會報錯(那塊內存已經被釋放了,被釋放了2次) //解決方案第二步--"="運算符重載 //詳情見 BBB 運算符重載的使用場景 p4 = p2; //BUG事例 p4 = p1; //分析:當執行p4 = p2; p4 = p1;仔細分析"="重載函數發現,p4 = p2;p4會開辟一塊內存N1, //p4 = p1;p4會再開辟一塊內存N2,此時N1這塊內存永遠不會被釋放,這就造成了內存泄漏 //為了解決這個問題 //解決方案第三步 //我們可以在執行"="重載函數之前判斷一下指針變量指向的內存又沒有釋放, //(所以要確定--定義對象的時候必須要分配指針變量的內存或者將指針變量置空) ///詳情見 CCC } void main(){ ProtectA(); system("pause"); }