2014-07-17 48 views
2

我有需要給他們由常量左值(其中將被複制)和右值引用(速度)C++,採取常量左值和右值引用在函數

struct Object { 
    ... 
    Object(Object&& o) { ... } 
    Object(const Object& o) { ... } 
    ... 
}; 

... 

struct SomeClass { 
    ... 
    Object arr[7]; 

    void copy(int pos,const Object& o) { arr[pos] = o; } 
    void copy(int pos,Object&& o) { arr[pos] = o; } 
    ... 
}; 
採取可變能力的幾種方法

因此,兩個複製方法在SomeClass中是完全相同的。唯一的區別是在一個對象中被傳遞爲const,它將被複制,並且在另一個對象被傳遞給一個快速拷貝作爲右值引用被使用。

這兩種方法的代碼是完全相同的。

現在,在上面的例子中沒有那麼悲慘,但是,我的方法有點大了,大約9-15行左右。顯然,解決方法是像複製它們一樣複製它們,但它感覺不對。

如何重新使用複製方法的代碼?

+3

你可以通過值和'std :: move'在函數中獲取參數。 – Praetorian

+0

好吧,Object類使用右值引用構造函數來「竊取」o對象的成員變量,並讓給定的對象不做任何事情。雖然const Object構造函數不能修改對象,也不能竊取它的變量,所以它必須複製。 –

+0

@Praetorian這是一個好主意。如果我沒有找到別的方法而沒有複製任何東西,我可能會使用它。 –

回答

2

通用參考和std::forward允許您實現完美轉發。這裏的修改copy

template <typename T> 
void copy(int pos, T&& o) {arr[pos] = std::forward<T>(o);} 

如果你擔心其他類型Object可能隱式轉換,也可以在copy正文中添加一個static_assert。如果您將l值Object傳遞給copy,則T將推斷爲Object&std::forward<Object&>返回一個參考。所以,複製分配過載將被選中。如果您通過r值Objectcopy,T將推斷爲Objectstd::forward<Object&>返回Object&&。由於std::forward<Object>(o)也是一個右值,移動賦值操作符將被選中。

+0

完美!我只是難過地採取另一個最好的答案,並把它給你:( –

3

首先,你在這兩種情況下做一個拷貝賦值:

void copy(int pos,const Object& o) { arr[pos] = o; } 
void copy(int pos,Object&& o) { arr[pos] = o; } 

如果它有一個名字,這是一個左值。在第二個函數中,o有一個名稱,所以它是一個左值(儘管是右值引用)。你想要arr[pos] = std::move(o);

通常的方式,以避免不必編寫copy兩次是通過值採取o和從它移動:

void copy(int pos, Object o) { arr[pos] = std::move(o); } 

o將如果傳遞左值被複制構造,然後將分配到arr[pos] 。如果你傳遞一個右值,o將被移動構造,然後進一步移動 - 分配到數組中。所以你仍然要避免在右值情況下的副本,但你在這兩種情況下支付額外的移動。如果移動像他們應該那樣便宜,它不會有太多的額外開銷。

但是,請注意,這不適用於不支持移動語義的遺留類型。在這種情況下,這個函數將複製你傳遞的內容,然後從中複製分配,而兩個引用的重載只會執行一個副本。

+0

那麼,你建議用這個替換這兩個?但是,如果SomeClass的用戶在調用副本時想要自己使用std :: move,該怎麼辦? sc.copy(0,std :: move(tempobj)); 或者我沒有正確理解你? –

+0

哦,好吧,我明白了,這個變體構造了兩次右值。我喜歡! –

+0

@VanillaFace如果你像'std :: move'那樣傳遞一個右值,那麼'o'將會移動,然後移動到數組中。 –

相關問題