2013-03-09 141 views
0

我有下面的代碼:拷貝構造函數和函數返回的臨時

struct balls 
    { 
     int mNumBalls; 

     ~balls();  
    }; 

    inline balls::~balls() 
    { 
      // is not called in VS2010 when getBalls returns in monkey constructor 
    } 

    balls getBalls() 
    { 
     balls myBalls; 

     myBalls.mNumBalls = 5; 

     return myBalls; 
    } 

    struct monkey 
    { 
     balls mBalls; 

     monkey(); 
    }; 

    inline monkey::monkey() : mBalls(getBalls()) 
    { 
    } 

通過在VS2010調試器步進,我注意到balls析構函數不是調用時getBalls()回報在monkey()構造。這是在C++標準中定義還是僅僅在VC++上存在的一些優化?在這種情況下,我可以依賴不被調用的析構函數跨平臺嗎?

感謝

+0

'getBalls(){balls myBalls;返回myBalls; }''猴子{球m球; }'...大聲笑 – 2013-03-09 20:23:34

+0

更新,開心? :p – KaiserJohaan 2013-03-09 20:24:54

+0

我很高興與原始版本。任何讀「猴子球」的代碼都會給我的臉帶來微笑。 – 2013-03-09 20:31:11

回答

1

每個段落的C++ 11標準的12.8/31:

當滿足特定條件時,的實現允許省略類 對象的複製/移動施工甚至如果爲複製/移動操作選擇的構造函數和/或對象 的析構函數具有副作用。在這種情況下,實現將被忽略的複製/移動操作的源和目標視爲簡單地指向同一對象的兩種不同方式,並且銷燬該對象 發生在兩個對象沒有優化就被摧毀了。 複製/移動操作的這個省音,叫做複製省略,允許在下列情況下(其中 可以合併,以消除多個副本):

- 與類返回類型的函數返回語句中,當表達是 非易失性自動對象具有相同cvunqualified 類型作爲函數返回類型(不是函數或catch子句參數其他)的名稱,複製/移動操作可以通過省略構造 自動對象直接進入函數的返回值

- [...]

這是那些案件之一:

balls getBalls() 
{ 
    balls myBalls; 

    return myBalls; <== COVERED BY THE QUOTED PARAGRAPH 
// ^^^^^^^^^^^^^^ 
} 

,這是一個真正相關的一個,因爲它代表一個例外一般的「好像」的規則。 「」好像「規則基本上允許編譯器更改您編寫的代碼只要效果相同(」「就好像」它完全執行了您所寫的程序)。但是,在這種情況下,即使您的拷貝構造函數,移動構造函數或析構函數有副作用,也不能依賴編譯器創建臨時文件(或者而不是創建臨時文件!)。

2

你滿足複製省略,這是一個定義良好的機制。由執行決定不執行不必要的副本。

+0

有沒有這樣做的主要編譯器?我能否安全地依靠不被主要平臺調用的析構函數(比如說windows,osx,linux,android,ps3) – KaiserJohaan 2013-03-09 20:24:00

+0

@KaiserJohaan:不,你不能*依賴這個。這是編譯器的選擇。實際上,所有編譯器都會在大多數情況下執行此操作。但是,你不能假設任何事情。這是「似乎」規則的例外。 – 2013-03-09 20:25:45

+0

@KaiserJohaan:並不是說「析構函數永遠不會被調用」。你只有一個比你預期的副本少。當monkey對象被銷燬時,仍然會有一個析構函數調用。 – 2013-03-09 20:40:08

2

如果你想通過值返回一個複雜的結構,唯一可以避免不必要的構造和破壞的方法是使用移動語義。見How to: Write a Move Constructor

例如,如果您的類分配內存,移動構造函數允許您將內存的所有權從一個變量轉移到另一個變量。然後優化器將刪除冗餘存儲並對傳輸的變量進行空值檢查。