I just started working with c++11 r-values. I read some tutorials, but I haven't found the answer.
What is the best way (the most efficient way) to set a class variable? Is below code correct or not? (let's assume std::string has defined move constructor and assignment operator).
class StringWrapper
{
private:
std::string str_;
public:
StringWrapper() : str_("") {}
void setString1(std::string&& str) {
str_ = std::move(str);
}
void setString2(const std::string& str) {
str_ = std::move(str);
}
// other possibility?
};
int main() {
std::string myText("text");
StringWrapper x1, x2;
x1.setString?("text"); // I guess here should be setString1
x2.setString?(myText); // I guess here should be setString2
}
I know that compiler can optimize my code and/or I can use overload functions. I'd like to only know what is the best way.
Herb Sutter's advice on this is to start with the standard C++98 approach:
void setString(const std::string& str) {
str_ = str;
}
And if you need to optimize for rvalues add an overload that takes an rvalue reference:
void setString(std::string&& str) noexcept {
str_ = std::move(str);
}
Note that most implementations of std::string
use the small string optimization so that if your strings are small a move is the same as a copy anyway and you wouldn't get any benefit.
It is tempting to use pass-by-value and then move (as in Adam Hunyadi's answer) to avoid having to write multiple overloads. But Herb pointed out that it does not re-use any existing capacity of str_
. If you call it multiple times with lvalues it will allocate a new string each time. If you have a const std::string&
overload then it can re-use existing capacity and avoid allocations.
If you are really clever you can use a templated setter that uses perfect forwarding but to get it completely correct is actually quite complicated.