struct TestConstRef {
std::string str;
Test(const std::string& mStr) : str{mStr} { }
};
struct TestMove {
std::string str;
Test(std::string mStr) : str{std::move(mStr)} { }
};
After watching GoingNative 2013, I understood that sink arguments should always be passed by value and moved with std::move
. Is TestMove::ctor
the correct way of applying this idiom? Is there any case where TestConstRef::ctor
is better/more efficient?
What about trivial setters? Should I use the following idiom or pass a const std::string&
?
struct TestSetter {
std::string str;
void setStr(std::string mStr) { str = std::move(str); }
};
The simple answer is: yes.
The reason is quite simple as well, if you store by value you might either need to move (from a temporary) or make a copy (from a l-value). Let us examine what happens in both situations, with both ways.
From a temporary
One limitation: a class without an efficient move-constructor (such as std::array<T, N>
) because then you did two copies instead of one.
From a l-value (or const temporary, but who would do that...)
One limitation: the same... classes for which moving is akin to copying.
So, the simple answer is that in most cases, by using a sink you avoid unnecessary copies (replacing them by moves).
The single limitation is classes for which the move constructor is as expensive (or near as expensive) as the copy constructor; in which case having two moves instead of one copy is "worst". Thankfully, such classes are rare (arrays are one case).