Search code examples
c++stringstdmove

Assigning rvalue references while assigning string


I am learning about rvalue references and my brain is probably all over the place. But I wanted to test the std::move and rvalue references and below is the code snippet

string s1 = "hello";
{
    string&& s2 = std::move(s1);
    cout << s2 << endl;
}

cout << s1 << endl;

The output is the same in both the cases. "hello"

I was hoping that inside the block when creating s2, it would've called the move assignment operator, thus making sure that s1 didnt point to anything, but that didnt happen.

My rational is that string is carrying a pointer to char inside of it, so when the move pointer is called, it will move the memory allocation from Thus when I move from s1 to s2, printing s1 should cause problems.

What did I do wrong in my understanding.


Solution

  • For one thing,

    string&& s2 = std::move(s1);
    

    isn't an assignment at all; it's an initialization.

    And it's initialization of a reference, not an object. There is only one std::string in your program, named s1. Since you declared s2 as a reference, it refers to some other object - here that's s1. So no move constructor or move assignment operator needs to be called at all, and s1 can't be changed.

    If you wrote instead

    string s2 = std::move(s1);
    

    then this would in fact create a second std::string object named s2. It gets initialized using the move constructor.

    Or if the = is used on an object previously declared, not to introduce an initializer right after a declaration, then it's a true assignment:

    string s2;
    s2 = std::move(s1);
    

    Here s2 is first created using the std::string default constructor, and then modified using the std::string move assignment operator.

    But note that after a std::string move constructor or move assignment operator, the contents of the "moved-from" object are unspecified. In some cases, the Standard says exactly what a move operation will do, often making the moved-from object empty. But when not otherwise specified, it says only that the object is in a "valid but unspecified state". And std::string doesn't add any specific requirements, so the unspecified state is the result. So printing s1 after this might result in anything at all. (Practically speaking, if the std::string implementation uses the Small String Optimization, you might find that s1 has not been changed.)