Perfect Forwarding
介紹
Perfect Forwarding
Perfect Forwarding 指的是函式可以原封不動 (保持原 lvalue/rvalue 性質)地把資料傳給真正要建立的地方, 藉此可以省去中間傳遞時不必要的複製。
std::forward
std::forward 是一個 conditional cast, 如果傳入的參數原本是 rvalue 的話, 才會進行轉換, 把它轉成 rvalue。
相對的 std::move 是無論如何都會把傳入的參數轉成 rvalue。
template<class T>
void wrapper(T&& arg) // universal reference
{
// arg is always lvalue
foo(std::forward<T>(arg)); // Forward as lvalue or as rvalue, depending on T
}
emplace
在 C++11 之後 STL 內的資料結構都多了 emplace 相關的函式可以呼叫, 以 vector 為例:
push_back(mystring)
:copypush_back(std::move(mystring))
:moveemplace_back(mystring)
:copy,等同於push_back(mystring)
emplace_back(std::move(mystring))
:move,等同於push_back(std::move(mystring))
emplace_back("mydata")
:in-place construction
使用 emplace 版本的結果可能會等同於原本的版本, 但在直接傳入內部資料時, emplace 版本就會比較有效率。
搭配 Variadic Template
template<typename... Args>
void stepper::rturn(Args&&... args) const
{
turn(std::forward<Args>(args)..., true);
}
結論
- 對 rvalue reference 使用 std::move
Widget&&
是 rvalue referencevector<T>&&
是 rvalue reference
- 對 universal reference 使用 std::forward
T&&
是 universal referenceauto&&
是 universal reference
如果是會被 RVO/NRVO 優化掉的 local 物件,不要套用 std::move 或 std::forward
rvalue reference:
class Widget {
public:
Widget(Widget&& rhs) // rhs is rvalue reference
: name(std::move(rhs.name)),
p(std::move(rhs.p))
{ ... }
...
private:
std::string name;
std::shared_ptr<SomeDataStructure> p;
};
universal reference:
class Widget {
public:
template<typename T>
void setName(T&& newName) // universal reference
{ name = std::forward<T>(newName); }
...
};