c++中的匿名物件的去留問題和深拷貝淺拷貝
阿新 • • 發佈:2019-01-02
匿名物件的去和留問題:
匿名物件的去和留主要取決於你用什麼去接收這個物件, 具體如下:# include <iostream> using namespace std; class Test { private: int a; public: Test() { cout << "我是無參建構函式" << endl; } Test(int x) { a = x; cout << "我是有參建構函式" << endl; } Test(Test & obj) { cout << "copy建構函式" << endl; } ~Test() { cout << "解構函式" << endl; } void printA() { cout << " a = " << a << endl; } }; Test display2() { Test t1; return t1; // 這裡會呼叫一個解構函式和copy建構函式 } void display1() { Test t2 = display2(); // 上一篇文章中已經講到過, 如果這裡不加 Test t2 , // 那麼display2返回的匿名物件將會被析構掉,那麼現在呢? // 除錯發現進入display1函式之後 , 執行 Test t2 = display2(): 這行語句時並沒有再次進入建構函式,也沒進入解構函式 // 也就是說這次沒有建立新的物件, 同時也沒有析構物件, 那麼 t2 是不是就是代表了原來的匿名物件, 只不過現在已經有名字了? // 加入如下程式碼試一次, t2.printA(); // 輸出結果為: a = -858993460 // 從上面的分析可知, Test t2 並沒有建立物件然而t2卻已經是一個物件了。 所以只可能是 原來的匿名物件被顯示成 t2 了。 // 再繼續往下除錯, 進入 解構函式。 // 以上都是在windows vs2017 上面進行的 } void display3() { Test t3(2); t3.printA(); t3 = display2(); // 如果是按照這種方式會發生什麼? // 在 t3 = display2(); 這一行會進入一次解構函式, 說明匿名物件在這一行被析構了 // 但是是在等號之前解構函式等號之後析構? 換句話說, t3 還是不是原來定義的t3 t3.printA(); // 在vs2017中輸出結果為: // 我是有參建構函式 // a = 2 // 我是無參建構函式 // copy建構函式 // 解構函式 // 解構函式 // a = -858993460 // 解構函式 // 請按任意鍵繼續. . . // 結論:由輸出結果可知, 匿名函式是在賦值給t3之後才會被析構。 // 對輸出結果解釋:首先進入display3函式, 定義t3物件,並且呼叫其建構函式, 呼叫t3的printA()函式 // 輸出“我是有參建構函式” 和 “a = 2” // 然後進入display2函式, 定義t1物件, 並且呼叫其建構函式, // 輸出:“我是無參建構函式” // 然後return t1; 這句話會返回一個匿名物件並且呼叫copy建構函式, 還會將t1物件析構掉 // 輸出:“copy建構函式”“解構函式” // 在display3函式中, display1返回的匿名物件賦值給 t3 物件之後被析構掉 // 輸出:“解構函式” // 然後由於 t3 物件的 a 已經是原來匿名物件的 a 了, 而且匿名物件又是沒有初始化的, 所以 a 是一個垃圾值 // 輸出:“a = -858993460” // 然後display3執行完, t3 被析構掉 // 輸出:“解構函式” } int main(void) { // display1(); display3(); system("pause"); return 0; }
深拷貝與淺拷貝
這個程式會發生錯誤; 解釋: 如上圖所示, 因為 Test t2 = t1; 這句程式碼呼叫的copy建構函式是一個淺拷貝, 所以只是將 t1 裡面屬性的值放在 t2 裡面, 也就是說 t1 和 t2 的 p 都指向堆記憶體裡面同一塊地址, 但是在解構函式裡面卻釋放了兩次, 所以Error。 解決辦法:# include <iostream> # include <cstring> using namespace std; class Test { private: int len; char * p; public: Test(const char * myp) { len = strlen(myp); p = (char *)malloc(sizeof(len + 1)); strcpy(p, myp); } ~Test() { if (NULL != p) free(p); p = NULL; len = 0; } }; void display() { Test t1("helloworld"); Test t2 = t1;// error } int main(void) { display(); system("pause");
這樣就ok了, 當然c++裡面不止copy建構函式是取淺拷貝, 其實還有很多地方都是。比如" = "等等。# include <iostream> # include <cstring> using namespace std; class Test { private: int len; char * p; public: Test(const char * myp) { len = strlen(myp); p = (char *)malloc(sizeof(len + 1)); strcpy(p, myp); } // 深拷貝 Test(const Test & obj1) { len = strlen(obj1.p); p = (char *)malloc(len + 1); strcpy(p, obj1.p); } ~Test() { if (NULL != p) free(p); p = NULL; len = 0; } }; void display() { Test t1("helloworld"); Test t2 = t1; } int main(void) { display(); system("pause"); return 0; }