-2

std::string str1 = "hello";
std::string &&str2 = std::move(str1);
std::string str3(str2);
std::cout << str1 << std::endl;

I think at line 3 that str3 will steal str1, because std::string(std::string &&str) (or sth. like that) will be invoked. But the result is:

test_move()
hello
test_move()

I want to know why the content str1 is still there after line 3.


std::string str1 = "hello";
std::string &&str2 = std::move(str1);
std::string str3(str2);
std::cout << str1 << std::endl;

std::string str4(std::move(str1));
std::cout << str1 << std::endl;

I try to move str1 directly to str4, and the result is:

test_move()
hello 

test_move()

So I can't figure out the difference between the situation of str4 and str3. In my eyes they are all the same, all takes a rvalue ref as parameter, but move semantics takes place only on str4.Why?

  • 1
    `str2` is l-value that is r-value reference, `std::string &&str` is not invoked and `str3(str2)` does not move `str1`. You might want `str3(std::move(str2))`. – 273K Dec 27 '22 at 03:34
  • After passing str1 to str4 with (``str4(std::move(str1))``) you shouldn't access value of str1, because after calling std::string(std::string&&) its argument is left in an undefined state - it may return the old value, cause a crash, or text your ex. You never know. – Bartosz Charuza Dec 27 '22 at 03:55
  • 2
    "Something about std::move" is really *not* a question. – bitmask Dec 27 '22 at 04:04
  • 1
    Search for _reference collapsing rules_, that will also give an explanation of what’s happening in this case. – Andrej Podzimek Dec 27 '22 at 04:21
  • Once you get the value categories worked out (so that your code actually uses the move constructor), see [A: Does std::string move constructor actually move?](https://stackoverflow.com/a/54420543) (For short strings, copying is faster than moving, so many implementations of the standard library will move short strings by copying them instead of stealing the data.) – JaMiT Dec 27 '22 at 05:47
  • 2
    @BartoszCharuza "*after calling std::string(std::string&&) its argument is left in an undefined state - it may return the old value, cause a crash, or text your ex. You never know.*" - Move semantics require the moved-from object to be left in a **valid but unspecified state**. It will not crash. But you are correct that it *could* return the old value (is, when a `string` uses SSO, which can't be moved, only copied) – Remy Lebeau Dec 27 '22 at 05:47

1 Answers1

1

std::move doesn't actually move anything. It merely creates an rvalue reference.

But since you initialize a variable with this rvalue reference, the variable itself becomes an lvalue. Passing the actual rvalue to an rvalue-constructor (as done in the second example) the constructor does the "moving".

If we create a small example program:

#include <iostream>
#include <utility>

struct Foo
{
    Foo() = default;

    Foo(Foo const&)
    {
        std::cout << "l-value copy construction\n";
    }

    Foo(Foo&&)
    {
        std::cout << "r-value move construction\n";
    }
};

int main()
{
    {
        Foo a;
        Foo&& b = std::move(a);
        Foo c(b);
    }

    {
        Foo a;
        Foo b(std::move(a));
    }
}

If you build and run it then you will see that it will invoke the lvalue copy constructor for your first case.

See it running e.g. here

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • I still can't understand why rvalue constructor is not invoked, I think compiler will treat str2 as a rvalue ref and that's what str2 defined to be. – chaowen Dec 27 '22 at 04:50
  • @chaowen Generally, if something has a name (which all variables have) then it's an lvalue. – Some programmer dude Dec 27 '22 at 05:00
  • 1
    `std::move` does not create an rvalue reference, tvalue references are lvalues. It creates an rvalue. A rvalue reference is what you usually use `std::move` on to turn it from an rvalue reference into an rvalue. Actually an xvalue which is a type of rvalue with identify as opposed to a prvalue which is an rvalue without identity. It can be confusing but is important. – doug Dec 29 '22 at 02:44
  • 1
    @chaowen [This value category reference](https://en.cppreference.com/w/cpp/language/value_category) is complex to read, but it's important to know about. – Some programmer dude Dec 29 '22 at 03:40
  • @ yep. Value categories can be confusing at first but once you wrap your head around it things get a lot clearer and more intuitive. – doug Dec 30 '22 at 02:35