C++構造函數、拷貝構造函數、賦值運算符重載 調用時機 GCC與VC在對象作爲返回值的不同處理

寫一個簡單的類來測試構造函數、拷貝構造函數、賦值運算符重載的調用時機。
一個小技巧:cout << this 可以查看當前對象的所在的地址,把它寫在某成員函數中,可以檢驗是哪個對象調用了當前成員函數。
#include <iostream>
using namespace std;




class A {
private:
int data;

public:
A() {
cout << this << " -> constructor " << endl;
}
A(const A& other) {
cout << this << " -> copy constructor " << endl;
}
A& operator=(const A& rhs) {
cout << this << " -> assignment constructor " << endl;
return *this;
}
~A() {
cout << this << " -> destructor " << endl;
}

A operator+(const A& rhs) {
cout << this << " -> overloading add operator " << endl;
this->data += rhs.data;
return *this;
}


};


A addTwo(A a1, A a2) {
cout << "call addTwo() " << endl;
return a1; //拷貝構造函數?
}


A func(A a1) {
cout << "call func() " << endl;
A b1 = a1; //拷貝構造函數
return b1;  //拷貝構造函數?


}


int main() {
A a; //A的構造函數
A b; //B的構造函數
b = addTwo(a, a); //賦值構造函數
b = func(a);

return 0;
}
用GCC編譯器對上述源代碼進行編譯執行,結果如下:
0x22ff28 -> constructor               //main()中的對象a
0x22ff24 -> constructor               //main()中的對象b
0x22ff30 -> copy constructor           //對象a作爲參數傳遞給addTwo()
0x22ff34 -> copy constructor           //對象a作爲參數傳遞給addTwo()
call addTwo()
0x22ff2c -> copy constructor           //addTwo()中 a1+a2 產生一個臨時對象作爲返回值
0x22ff24 -> assignment constructor    //地址爲0x22ff24,與main()中對象b相同,表明這是main()中對象b得到賦值
0x22ff2c -> destructor
0x22ff34 -> destructor
0x22ff30 -> destructor
0x22ff3c -> copy constructor     //對象a作爲參數傳遞給func()
call func()
0x22ff38 -> copy constructor    //func()中,對象b1被賦值爲a1  
0x22ff24 -> assignment constructor   //main()中,對象b得到賦值
0x22ff38 -> destructor
0x22ff3c -> destructor
0x22ff24 -> destructor
0x22ff28 -> destructor
結論:普通構造函數的調用時機自不多說;
拷貝構造函數的調用時機有:
1)一個對象以值傳遞的方式傳入函數體; (addTwo()、func()的參數傳遞)
2)一個對象以值傳遞的方式從函數體返回;(addTow()返回值,注意func()在返回時沒有調用拷貝函數!!!後面解釋)
3)一個對象需要通過兩外一個對象進行初始化;(func中對象b1需要用a1進行初始化)
賦值運算符重載的調用時機:
在一個對象已經創建之後,對其進行賦值時,就會調用該對象的賦值運算符函數。


在VC編譯器上編譯和執行同樣的源代碼,結果如下:
0012FF70 -> constructor            //main()中的對象a
0012FF6C -> constructor             //main()中的對象b
0012FEE4 -> copy constructor         //...
0012FEE0 -> copy constructor         //...
call addTwo()
0012FF60 -> copy constructor         //...
0012FEE0 -> destructor
0012FEE4 -> destructor
0012FF6C -> assignment constructor    //...
0012FF60 -> destructor
0012FEE4 -> copy constructor
call func()
0012FEC8 -> copy constructor         //func()中,對象b1被a1賦值
0012FF58 -> copy constructor         //func()返回時創建臨時對象!!! 這在上面的結果中是沒有的
0012FEC8 -> destructor
0012FEE4 -> destructor
0012FF6C -> assignment constructor
0012FF58 -> destructor
0012FF6C -> destructor
0012FF70 -> destructor
Press any key to continue
結論:
C/C++ 函數參數和返回值傳遞機制
指出:GCC 編譯器不創建額外的返回值臨時對象(即使用-O0參數來關閉優化)
對此,並未給出詳細說明,從上述測試代碼中可以看出,當被調用函數中創建本地的對象並作爲返回值時,就不會再創建臨時對象。
我還注意到,如果被調用函數返回的對象正是傳遞給它的參數之一,這時仍然會創建臨時對象。
而VC編譯器的表現則和我們常規理解保持一致。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章