閱讀1021 返回首頁    go 微軟 go windows


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;
}

以上兩個運行結果截圖分別來自VSg++

    看到這個輸出,相信不少人和我一樣有疑惑:為什麼沒有調用拷貝構造函數?在回答這個疑問之前,我們先解決另外一個疑問——使用“=”創建的對象就一定要調用拷貝構造函數嗎?

     從運行結果來看是否定的,在創建x1,x2的時候,我們的預想是編譯器先創建一個臨時對象,在使用臨時對象作為拷貝構造函數的參數創建新對象。其實這裏編譯器采用了一種優化,叫做Named Return Value(NRV)。

Named Return value 優化:

nrv優化的本質是優化掉拷貝構造函數,去掉它不是生成它。當然了,因為為了優化掉它,前提就是它存在,也就是欲先去之,必先有之,這個也就是nrv優化需要有拷貝構造函數存在的原因。 nrv優化會帶來副作用,目前也不是正式標準,倒是那個對象模型上舉的應用例子看看比較好。極端情況下,不用它的確造成很大的性能損失,知道這個情況就可以了。  

為什麼必須定義了拷貝構造函數才能進行nrv優化?首先它是lippmaninside 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

  上一篇:go 文件操作函數fread/fwrite/fseek演示例程
  下一篇:go 談android界麵設計