[英]Accept move-only parameter by value or rvalue reference
這個帖子的接受答案通過價值與通過右值參考傳遞說明:
對於僅移動類型(如
std::unique_ptr
),pass-by-value似乎是常態......
我對此有點懷疑。 讓我們說有一些不可復制的類型, Foo
,它也不便宜移動; 和一些有成員Foo
類型Bar
。
class Foo {
public:
Foo(const Foo&) = delete;
Foo(Foo&&) { /* quite some work */ }
...
};
class Bar {
public:
Bar(Foo f) : f_(std::move(f)) {} // (1)
Bar(Foo&& f) : f_(std::move(f)) {} // (2)
// Assuming only one of (1) and (2) exists at a time
private:
Foo f_;
};
然后為以下代碼:
Foo f;
...
Bar bar(std::move(f));
構造函數(1)引發2個移動構造,而構造函數(2)只引發1.我還記得在Scott Meyers的Effective Modern C ++中讀到這個但是不能立即記住哪個項目。
所以我的問題是,對於僅移動類型(或者更一般地說,當我們想要轉移參數的所有權時),我們是否應該更傾向於通過rvalue-reference來獲得更好的性能?
更新:我知道pass-by-value構造函數/賦值運算符(有時稱為統一 ctors /賦值運算符)可以幫助消除重復的代碼。 我應該說我對以下情況更感興趣:(1)性能很重要,(2)類型是不可復制的,因此沒有重復的ctors /賦值運算符接受const
左值引用參數。
更新2:所以我找到了Scott Meyers關於具體問題的博客: http : //scottmeyers.blogspot.com/2014/07/should-move-only-types-ever-be-passed.html 。 這篇博客討論了他在有效現代C ++第41項中提倡的原因:
考慮僅為可復制參數傳遞值... 移動便宜 ...... [和] 總是被復制 。
在該項目中有關於按值傳遞與右值參考的廣泛討論,這里引用太多。 關鍵是,兩種方式都有各自的優點和缺點,但是為了轉移僅移動對象的所有權,通過右值引用似乎更可取。
在這種情況下,我們可以吃蛋糕然后吃。 僅為類似Foo的引用啟用的模板構造函數為我們提供了完美的轉發以及構造函數的單個實現:
#include <iostream>
#include <utility>
class Foo {
public:
Foo() {}
Foo(const Foo&) = delete;
Foo(Foo&&) { /* quite some work */ }
};
class Bar {
public:
template<class T, std::enable_if_t<std::is_same<std::decay_t<T>, Foo>::value>* = nullptr>
Bar(T&& f) : f_(std::forward<T>(f)) {} // (2)
// Assuming only one of (1) and (2) exists at a time
private:
Foo f_;
};
int main()
{
Foo f;
Bar bar(std::move(f));
// this won't compile
// Foo f2;
// Bar bar2(f2);
}
很難想象一個移動成本昂貴的類:移動語義完全取決於語義允許時快速替換副本的需要。
您帶來了std::string
和SSO的示例。 然而,這個例子顯然存在缺陷(我懷疑他們甚至開啟了優化),因為通過memcpy
復制16個字節應該占用一堆CPU周期,因為它可以在1個SIMD指令中實現,以便一次性存儲它們。 此外,MSVC 10真的很老了。
所以我的問題是,對於僅移動類型(或者更一般地說,當我們想要轉移參數的所有權時),我們是否應該更傾向於通過rvalue-reference來獲得更好的性能?
我不會談論性能,因為它是如此奇特的方面,不能“一般”分析。 我們需要具體案例。 此外,還需要考慮編譯器優化; 實際上相當重。 不要忘記徹底的性能分析。
std::unique_ptr
是有點不同的,因為(ⅰ)只能被移動,由於擁有語義(ii)其是便宜的移動。
我的觀點。 我想說如果你必須提供一個“更快”的替代品作為API,提供兩者 - 就像std::vector::push_back
。 正如你所說,它可能會有輕微的改進。
否則,即使對於僅移動類型,通過const-reference傳遞仍然有效,如果你認為它不會,則轉換為pass-by-value。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.