什么是臨時對象?
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參數時,極可能一個臨時對象綁定到該參數上;
- 當我們看到函數返回一個對象時,就會產生臨時對象。