C++構造函數、拷貝構造函數、賦值運算符漫談(三)——NRV
//
首先看下麵一段程序:
class X { public: X() { cout<<"X()"<<endl; }; X(int v):val(v) { cout<<"X(int)"<<endl; } X(const X& x) { cout<<"X(const X& x)"<<endl; } X& operator=(const X&) { cout<<"="<<endl; return *this; } ~X() {cout<<"destructor"<<endl;} void memfun() { cout<<"memfun"<<endl; } private: int val; }; int _tmain(int argc, _TCHAR* argv[]) { X x0(1024); X x1=X(1024); X x2=(X)1024; }
以上兩個運行結果截圖分別來自VS和g++。
看到這個輸出,相信不少人和我一樣有疑惑:為什麼沒有調用拷貝構造函數?在回答這個疑問之前,我們先解決另外一個疑問——使用“=”創建的對象就一定要調用拷貝構造函數嗎?
從運行結果來看是否定的,在創建x1,x2的時候,我們的預想是編譯器先創建一個臨時對象,在使用臨時對象作為拷貝構造函數的參數創建新對象。其實這裏編譯器采用了一種優化,叫做Named Return Value(NRV)。
Named Return value 優化:
nrv優化的本質是優化掉拷貝構造函數,去掉它不是生成它。當然了,因為為了優化掉它,前提就是它存在,也就是欲先去之,必先有之,這個也就是nrv優化需要有拷貝構造函數存在的原因。 nrv優化會帶來副作用,目前也不是正式標準,倒是那個對象模型上舉的應用例子看看比較好。極端情況下,不用它的確造成很大的性能損失,知道這個情況就可以了。
為什麼必須定義了拷貝構造函數才能進行nrv優化?首先它是lippman在inside c++ object mode裏說的。那個預先取之,必先有之的說法隻是我的思考。查閱資料,實際上這個可能僅僅隻是cfont開啟NRV優化的一個開關。
The C++ standard allows the elision of the copy constructor (even if this results in different program behavior), which has a side effect of enabling the compiler to treat both objects as one。也就是我說的副作用,c++標準允許這個副作用的出現,也就是它允許進行NRV優化,但不是必須。
最後更新:2017-04-03 12:55:57