2015-11-06 52 views
5

當我想要一個函數返回我的容器:返回值優化:我可以避免複製構建巨大的STL容器。

vector<T> func(){ 
    vector<T> result; 
    ... 
    return result; 
} 

要在下列方式使用:

vector<T> result = func(); 

爲了避免抄襲我的容器 的開銷,我經常寫函數,以便它只返回一個容器的非常量實例。

void func(vector<T>& result){ 
    result.clear(); 
    ... 
    result; 
} 

以下列方式使用:

vector<T> result; 
func(result); 

是我的努力毫無意義的,因爲我可以肯定的是,編譯器 始終使用返回值優化?

+1

由於C++ 11你的努力是沒有意義的,直到C++ 11是正確的做法。 – 101010

+0

即使在C++ 03中,您也應該使用第一個代碼示例。 – Simple

+0

您認爲RVO(如果應用)將與其他方式一樣有效。情況並非總是如此。 –

回答

10

這是沒有意義的。您提到的RVO類型稱爲RVO(NRVO),並且大多數編譯器都實現它。

無論如何,在C++ 11中,vector都有移動構造函數,所以即使NRVO不適用,它仍然會被移動,而不會被複制。

2

RVO不能保證,但體面的編譯器會在允許的情況下使用它。

但是,問題是RVO只有在您在函數外部創建新對象時纔有所幫助。如果通過引用傳遞它來重用相同的向量,則可以利用其保留的容量來減少內存分配的數量。在函數內部創建的局部向量總是需要在內部分配新的緩衝區,而不管返回值的存儲位置。因此,通過引用傳遞向量可能更有效,即使代碼看起來不太好。

2

取決於編譯器的年齡。在C++ 11之前,除非編譯器支持命名的返回值優化,否則您的替代方法是需要的,而不是所有較老的編譯器都這樣做。另外,你也可以讓函數返回一個對傳入向量的引用。

從C++ 11開始,語言支持移動構建,而標準容器有工作移動構造函數,所以你的第一種方法很好。純粹主義者會堅持認爲更好。實用主義者(意識到不是每個人都可以更新編譯器而沒有巨大的潛力)會根據代碼是否需要繼續使用C++ 11之前的編譯器和更高版本的編譯器來選擇解決方案。

+0

即使使用較舊的編譯器,您也可以體驗它是否實現複製elision。 –

+0

的確,M.M.或者閱讀編譯器文檔。但是,仍然需要使用多個編譯器(甚至是編譯器版本和設置),操作系統之間的代碼等。 – Peter

0

我試過用gcc。我意識到,編譯時如果沒有C++ 11標誌,我不能依賴NRVO。

因爲我不喜歡第二個簽名(其中功能通過引用,採用的容器),我來到了這一點:

聲明函數的自然形態:

vector<T> func(){ 
    vector<T> result; 
    ... 
    return result; 
} 

和,當我不知道的編譯器和編譯標誌,這樣使用它:以這種方式

vector<T> result; 
func().swap(result) 

一個得到想要的界面,是一定要避免過度elidible頭。

注意,result向量的容量是由該函數返回的矢量中的所述一個。如果想爲矢量設置容量,則該函數的右側界面是第二個。

+0

交換和傳遞參考看起來都很醜陋。你也可以堅持參考方法。 –

+0

IMO交換優於參考方法,因爲交換不涉及聲明。函數的簽名更具可讀性(在我的示例中,不會返回任何向量)。 – jimifiki

+0

參考方法可以利用現有的矢量容量。在高性能應用程序中,有時您爲了速度必須犧牲一些代碼的好處。 –