2012-12-17 51 views
3

假設有一個返回std::set的方法:C++返回一個類到一個const引用或不?

std::set<string> MyClass::myMethod() const 
{ 
    std::set<string> result; 
    // ... some code to fill result ... 
    return result; 
} 

在發送方,我們可以存儲的myMethod結果在兩個方面:

void MyClass::test() 
{ 
const std::set<string> s1 = myMethod(); // 1 
const std::set<string>& s2 = myMethod(); // 2 (using reference) 
// ... some code to use s1 or s2 ... 
} 

我的問題是:

  • 他們之間有什麼區別嗎?
  • 哪種方式更好, 高效?

回答

3

從理論上講,第二個版本更好,因爲它不需要額外的副本。

實際上,RVO可能會踢進去,所以他們應該大致相同。

+0

是否第一個版本需要拷貝(RVO除外),如果該類型有一招構造函數和/或移動賦值運算符? – Kos

+0

在實踐中,你更喜歡哪種方式? – deepmax

+0

@MasoudM。首先。 –

4
const std::set<string> s1 = myMethod(); // 1 

myMethod的返回複製到s1中。根據大小,這可能需要很長時間。

const std::set<string>& s2 = myMethod(); // 2 (using reference) 

存儲對由myMethod返回的臨時文件的引用。這導致比上述方法少一個副本,所以它稍微快一點(假設沒有優化)。

這是一個special case feature,用於引用一個變量,否則該變量會在該;處停止存在。這隻適用於const&,在你的例子中,或者Rvalue引用 - &&(謝謝@Kos)。

+0

不僅'const&',這也適用於'&&'。 – Kos

+0

@Kos這是一個右值引用isnt它..恐怕我還沒有更新自己的移動語義和相關的變化呢..請隨時編輯和添加詳細信息。 –

+0

在C++ 03中,引用將(或可以)初始化爲引用副本,而不是返回的對象。在形式上,兩者沒有區別。 –

2

是的,這些是不同的:

  1. const std::set<string> s1 = myMethod(); // 1:複製臨時對象

  2. const std::set<string>& s2 = myMethod(); // 2 (using reference):臨時的壽命延長,它避免一個拷貝

Guru of the week #88。請注意,編譯器可以通過使其效率相同來優化這一點。

+0

請注意,編譯器可以「引導」引用的初始化以使用副本。 –

1
  1. 第一個版本將創建std::set對象,它會在該線移動

    const std::set<string> s1 = myMethod();

  2. 這將延伸在所述方法中產生的std::set對象的生命週期:

    const std::set<string>& s2 = myMethod();

因此,性能方面都做同樣的事情。

2

在實踐中不可能有任何差異。我測試過用g++ 4.7.2如下:

#include <string> 

extern std::string f(); 
extern void g(const std::string&, const std::string&); 

int main() { 
    std::string  x = f(); 
    const std::string& y = f(); 
    g(x, y); 
} 

而且它產生了兩個電話相同的代碼f()

LEHB0: 
     call __Z1fv 
LEHE0: 
     leaq 16(%rsp), %rdi 
LEHB1: 
     call __Z1fv 
LEHE1: 
     leaq 16(%rsp), %rsi 
+1

+1不錯的測試,可移植性如何?我們可以相信所有的C++編譯器都有相同的輸出嗎? – deepmax

+0

@MasoudM .:我們顯然不能指望* all *編譯器以任何特定的方式運行。但是,我希望有一個好的編譯器來執行這個優化。 – NPE

+0

哪種方式更好,你通常選擇? – deepmax

相關問題