2012-05-31 90 views
14

我有一個簡單的類:我應該使用rvalues編寫std :: string構造函數嗎?

class X 
{ 
    std::string S; 
    X (const std::string& s) : S(s) { } 
}; 

我讀過一些關於右值最近,我一直在想,我是否應該使用右值寫構造函數X,這樣我就可以做臨時檢測std::string類型的對象?

我認爲它應該是這個樣子:

X (std::string&& s) : S(s) { } 

至於我所知,在編譯器支持C++ 11應該使用它執行的std :: string的的可用時移動的構造。

+2

[相關](http://stackoverflow.com/questions/7592630/is-pass-by-value-a-reasonable-default-in-c11)。 –

+0

引用的代碼是一個破碎的模式,它包含了兩個世界中最糟糕的代碼:它約束調用者被要求傳遞一個右值給'X()',但是它不能將右值轉發給'S'的構造函數,因此它不能移動並且必須複製。所以,它給這個功能的使用者帶來了負擔,同時阻止他們獲得任何補償性的回報。 –

+0

@underscore_d我認爲五年後,我們已經就答案達成了一致意見,我的代碼並不完美;) –

回答

23
X (std::string&& s) : S(s) { } 

這不是一個構造函數服用右值,但構造服用右值引用。在這種情況下,您不應該採用右值引用。而是按值傳遞,然後移動成員:

X (std::string s) : S(std::move(s)) { } 

經驗法則是,如果你需要複製,這樣做的接口。

+3

爲什麼他不應該有一個構造函數在這種情況下接收右值引用? – ncasas

+2

@ncasas:組合爆炸? –

+6

@ncasas:那麼你需要提供'X(std :: string &&)'和'X(std :: string const&)'(用於構造對象的參數是* lvalue * )。這些替代品很容易由編譯器在* pass-by-value *構造函數中管理,參數將使用現有構造函數從std :: string(std :: string const&)或std :: string(std :: string &&)'來創建副本。也就是說,只提供按值構造函數,編譯器可以使用庫的功能,而不用重寫它。 –

13

不,你不應該。你應該做的是一個這樣的替換當前的構造函數:

X (std::string s) :S(std::move(s)) {} 

現在,你可以同時處理左值,這將被複制到參數上,然後移動到你的類的字符串,R值,這將被移動兩次(您的編譯器希望可以優化這些額外的工作)。

在大多數情況下(也有例外,我不會進入這裏),你不應該寫這樣取r值的引用,除了你寫的類的舉動構造函數。任何時候你需要你自己的一個值的副本,這並不僅僅適用於構造函數,你應該把它放在價值中,並把它移到需要去的地方。您可以讓類自己的移動構造函數根據是否接收r值或l值來決定是應該複製還是移動該值。總而言之,引入了r值引用使我們的生活更輕鬆,更難。

+0

我在想,除了移動構造函數(顯然還有標準庫提供的'move'和'forward''函數),rvalue-references是否有其他用途。你知道一些其他應該使用右值引用的情況嗎? –

+0

@LucTouraille:在模板功能允許完美轉發。例如'emplace_back','make_shared' –

+0

噢,當然!我引起了「前鋒」,甚至沒有考慮它的目的...... –

5

因爲你所需要的參數的副本,由值取參數。然後,將其轉移到您的會員資料中。它是std::string構造函數,它負責檢測給出的參數是右值還是左值,而不是你。

class X 
{ 
    std::string s_; 
    X(std::string s) : s_(std::move(s)) {} 
}; 
19

在澄清的興趣:通過噪聲值的答案是沒有錯的。但是,無論是你的加入string&&過載,除了一個細節的第一個猜測:

地址:

X (std::string&& s) : S(std::move(s)) { } 

即您仍然需要move,因爲雖然s具有與string相關的右值的聲明類型,但用於初始化S表達式sstring類型的左值表達式。

事實上,您首次提出的解決方案(隨着移動的添加)比傳遞值解決方案稍快。但兩者都是正確的。傳遞值解決方案在將lvalue和xvalue參數傳遞給X的構造函數時會額外調用字符串的移動構造函數。

在左值參數的情況下,無論如何都會創建一個副本,並且字符串的複製構造函數可能比字符串的移動構造函數昂貴得多(除了適合短字符串緩衝區的字符串,在這種情況下,移動和複製速度大致相同)。

對於xvalue參數(xvalue是已傳遞給std::move的左值)的情況下,傳值解決方案需要兩個移動構造而不是一個。所以它比rvalue參考解決方案的價格貴一倍。但仍然非常快。

這篇文章的要點是要明確:傳值是一個可接受的解決方案。但它不是唯一可接受的解決方案。使用pass-by-rvalue-ref進行重載的速度更快,但缺點是所需的重載次數隨着參數N的增長而變爲2^N。

相關問題