c++c++11rvalue-referencervaluepass-by-rvalue-reference

What is the most efficient way to set class variable using rvalue in c++?


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.


Solution

  • 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.