C++之临时对象的构造与析构
1、臨時對象產生的時間點
對象作參數(值傳遞)、返回對象(值傳遞)
2、臨時對象析構的時間點(重點、難點)
3、臨時對象會降低效率,但是哪些情況必須使用臨時對象?
【注】真正的臨時對象是看不見的,它不會出現在程序代碼中。
示例:
> 【提示】代碼中有輸出this,主要是在單步調試的時候方便觀看構造、拷貝、析構的是哪一個對象!#include <iostream> using namespace std; class A { public:A(){cout<<"構造"<<this<<endl;}A(const A& a){cout<<"拷貝"<<this<<endl;}virtual ~A(){cout<<"析構"<<this<<endl;} }; void f1(A aa) { cout<<"aa = "<<&aa<<endl;//加入此句目的:為了判斷copy出來的臨時對象temp是否和形參對象a是一個對象(答案:是!)//傳參數時,調用copy構造臨時對象temp,temp和形參aa的地址一樣,即temp和aa實質上是一個對象!(只析構temp順帶著aa也就被析構了!) } A f2() {A aa; //構造局部對象aareturn aa; //①先return時拷貝構造產生一個臨時對象temp;②然后析構局部變量aa,當退出f2()函數時并沒有析構臨時對象。 } A f3(A aa) {cout<<"a = "<<&a<<endl;return aa;//傳參數時創建臨時對象temp1,temp1 = aa//return時創建臨時對象temp2,temp2是否等于main函數中的被賦值的對象分兩種情況! //case1: A t1; t1 = f3(t); 臨時對象temp2!= 對象t1 //case2: A t1 = f3(t); 臨時對象temp2 = 對象t1 }情況一:
int main() {A a1; //構造函數f1(a1);return 0; }【解釋】執行f1(a1);時,執行情況:①調用拷貝構造生成臨時對象temp并賦值給形參中的aa(temp和aa是同一個對象);②當退出void f1(A aa)函數時,臨時對象temp析構(因為aa離開了作用域,aa析構就等同于temp析構);③return 0;析構main中的a1。
【執行結果】構造、拷貝、析構、析構
情況二:
int main() {A a1;A a2;a2 = f2(); cout<<"a2 = "<<&a2<<endl;return 0; }【解釋】執行到a2 = f2(); 時,執行情況是:①進入f2()函數,先構造局部對象aa;②return aa; 這行的執行情況:先拷貝構造一個臨時對象temp,然后碰到return aa;的分號時刻析構局部對象aa;退出A f2()函數體③繼續執行語句a2 = f2();中的“=”號運算符,相當于a2=temp;即把臨時對象temp的值賦值給a2.(注:但是temp和a2不是同一個對象,兩個都需要析構) ④執行完a2 = f2();語句中的“=”號,就碰到分號“;”,此時臨時對象temp被釋放。⑤return 0;時依次析構main函數中的a2、a1
【執行結果】構造、構造、構造、拷貝、析構、析構、析構、析構
情況三:
int main() {A a = f2();cout<<"a = "<<&a<<endl;return 0; }【解釋】A a2 = f2();語句的執行情況:①先執行f2(),進入f2()函數體,構造局部對象aa;②再執行return aa;語句:return aa調用拷貝構造創建一個臨時對象temp;之后碰到return aa;語句的分號時,析構對象aa。退出f2()函數體 **③執行A a = f2();語句的“=”號運算符,把臨時對象temp賦值給對象a(注:此時temp和a是同一個對象,只需要析構一個,另一個也就釋放掉)。
【重點】:由于編譯器的優化作用,A a =f2();語句并沒有調用拷貝構造函數創建對象a,編譯器省略了這次拷貝構造,因此temp和a是同一個對象,只需要析構一個,另一個也就釋放掉——>臨時對象temp析構的時間就是main函數中對象a的時間
- ④return 0;語句執行時,析構臨時對象temp(即a也沒有了)。*
【執行結果】構造、拷貝、析構、析構
情況四:
int main() {A a1;A a2 = f3(a1);cout<<"a2 = "<<&a2<<endl;return 0; }【解釋】A a2 = f3(a1);執行情況:①先執行 f3(a1)進入函數體,copy構造臨時對象temp1,并賦值給形參aa(此時temp1和aa是同一個對象),②return aa;語句執行情況:先拷貝構造臨時對象temp2,再析構對象aa(因為此時離開了aa的作用域,temp1也不存在了),退出函數體。③執行A a2 = f2(a1);的“=”號,此時不調用拷貝構造函數,只把臨時對象temp2賦值給a2(原因同情況三,temp2和a2是同一個對象,只需要析構一個,另一個也就釋放掉)。④return 0;時釋放臨時對象temp2(即a2也不存在了),再釋放main函數中的a1對象。
【執行結果】構造、拷貝、拷貝、析構、析構、析構
情況五:
int main() {A a1;A a2 ;a2 = f3(a1);cout<<"a2 = "<<&a2<<endl;return 0; }【解釋】a2 = f3(a1);執行情況:①先執行 f3(a1)進入函數體,copy構造臨時對象temp1,并賦值給形參aa(此時temp1和aa是同一個對象),②return aa;語句執行情況:先拷貝構造臨時對象temp2,再析構對象aa(因為此時離開了aa的作用域,temp1也不存在了),退出函數體。③a2 = f3(a1);語句執行情況:先“=”號運算符把臨時對象temp賦值給a2(注:temp2和a2不是同一個對象,要析構兩次),碰到“;”號時析構臨時對象temp2。④return 0;依次析構a2、a1
【執行結果】構造、構造、拷貝、拷貝、析構、析構、析構、析構
綜上所述:
臨時對象構造時間點是在下面兩個:
對象作參數(值傳遞)、返回對象(值傳遞)
臨時對象析構時間點比較復雜,具體情況具體分析,主要分為兩類:
【解決問題的關鍵在于】判斷臨時對象和被臨時對象賦值的對象是不是同一個對象?
(1)若不是同一個對象,則臨時對象的析構時間是main的主調函數語句的“;”號時刻。
(2)若是同一個對象,則臨時對象的析構時間就是main的主調函數語句中被臨時對象賦值的對象的析構時間。
例如:
//case1: A t1; t1 = f3(t); 臨時對象temp2!= 對象t1
臨時對象析構時間:執行到t1 = f3(t); 語句的“;”號時刻!
//case2: A t1 = f3(t); 臨時對象temp2 = 對象t1
臨時對象析構時間:就是t1對象的析構時間!
講解的這么詳細,在聽不懂真對不起我。
【友情提示】 可以復制上面的代碼用VS進行單步調試,調試鍵F10、F11。
2017/3/2
總結
以上是生活随笔為你收集整理的C++之临时对象的构造与析构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++之static关键字
- 下一篇: 彩色图批量转换成灰度图、批量格式转换、批