19. 了解臨時對象的來源


什么是臨時對象?

        C++真正的臨時對象是不可見的匿名對象,不會出現在你的源碼中,但是程序在運行時確實生成了這樣的對象.

通常出現在以下兩種情況:

(1)為了使函數調用成功而進行隱式類型轉換的時候

        傳遞某對象給一個函數,而其類型與函數的形參類型不同時,如果可以通過隱式轉化的話可以使函數調用成功,那么此時會通過構造函數生成一個臨時對象,當函數返回時臨時對象即自動銷毀。如下例:

//計算字符ch在字符串str中出現的次數
int countChar (const string& str, char ch);
char buffer[];
char c;
//調用上面的函數
countChar (buffer, c);
 
        

      我們看的第一個參數為char[],而函數的參數類型為const string&,參數不一致,看看能否進行隱式轉化,string類有個構造函數是可以作為隱式轉化函數(參見5)的。那么編譯器會產生一個string的臨時變量,以buffer為參數進行構造,那么countChar中的str參數會綁定到此臨時變量上,直到函數返回時銷毀。

      注意這樣的轉化只會出現在兩種情況下:函數參數以傳值(by value)的方式傳遞 或者 對象被傳遞到一個 reference-to-const 參數上。

傳值方式:

 
        
int countChar (string str, char ch);
string buffer;
char c;
//參數通過傳值方式傳遞
countChar (buffer, c);
 
        

       這種方法會調用string的拷貝構造函數生成一個臨時變量,再將這個臨時變量綁定到str上,函數返回時進行銷毀。

 

傳常量引用:

       開始的實例即時屬於這種情況,但一定強調的是傳遞的是const型引用,如將開始函數的原型改為

 
        
int countChar (string& str, char ch);

       下面調用相同,編譯器會報錯!為什么C++設計時要求 當對象傳遞給一個reference-to-non-const 參數不會發生隱式類型轉化呢?

       下面的實例可能向你說明這樣設計的目的:

 
        
//聲明一個將str中字符全部轉化為大寫
void toUpper (string& str);
char buffer[] = "hazirguo";
toUpper(buffer);                 //error!!非const引用傳遞參數不能完成隱式轉化
 
        

        如果編譯器允許上面的傳遞完成,那么,會生成一個臨時對象,toUpper函數將臨時變量的字符轉化為大寫,返回是銷毀對象,但是對buffer內容毫無影響!程序設計的目地是期望對“非臨時對象”進行修改,而如果對reference-to-non-cosnt對象進行轉化,函數只會對臨時變量進行修改。這就是為什么C++中要禁止non-const-reference參數產生臨時變量的原因了。

 

(2)當函數返回對象的時候

        當函數返回一個對象時,編譯器會生成一個臨時對象返回,如聲明一個函數用來合並兩個字符串:

 
        
const string strMerge (const string s1, const string s2);
 
        
大多時候是無法避免這樣的臨時變量產生的,但是現代編譯器可以將這樣的臨時變量進行優化掉,這樣的優化策略中,有個所謂的“返回值優化”,下一篇具體講解。
 
總結:
臨時對象有構造和析構的成本,影響程序的效率,因此盡可能地消除它們。而更為重要的是很快地發現什么地方會生成臨時對象:
  • 當我們看到一個reference-to-const參數時,極可能一個臨時對象綁定到該參數上;
  • 當我們看到函數返回一個對象時,就會產生臨時對象。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM