1

I the following code I have explictly forbidden copying and moving Dummy object using delete specifier for copy and move constructors and for copy and move assignment operators:

#include <string>
#include <iostream>

struct Dummy
{
    explicit Dummy(const std::string& value) : value_(value) {}
    Dummy(const Dummy&) = delete;
    Dummy& operator=(const Dummy&) = delete;
    Dummy(Dummy&&) = delete;
    Dummy& operator=(Dummy&&) = delete;

    void print_this_address() const
    {
        std::cout << "this address: " << this << "\n";
    }

    std::string value_;
};

void foo(Dummy&& obj)
{
    std::cout << obj.value_ << "\n";
    obj.print_this_address();
}

int main()
{
    Dummy obj("42");
    obj.print_this_address();
    foo(std::move(obj));
    std::cout << obj.value_ << "\n";
    return 0;
}

This code compiles and runs well and I'm getting the following output in my terminal:

this address: 0x7ffeeb6d2a20
42
this address: 0x7ffeeb6d2a20
42

Can someone explains for me what's happening in this code and why I didn't get compile error and have the same object in foo function as in main. function?

Igor
  • 427
  • 4
  • 13

2 Answers2

3

It's not because you called std::move that your object has moved. It was just "prepared" to be moved.

As such, you prepared obj but never tried to move it somewhere else, hence the no compiler error, and as you never actually moved it (you just passed an rvalue reference to your object into foo), you get the same result, because obj never changed.

StoryTeller - Unslander Monica
  • 148,497
  • 21
  • 320
  • 399
Matthieu Brucher
  • 19,950
  • 6
  • 30
  • 49
  • Is it passed by reference as a result? – Igor Nov 18 '18 at 08:59
  • The parameter `Dummy &&obj` is an rvalue reference, a reference that can bind to rvalues but not to lvalues. So the object _is_ passed by reference. – Pezo Nov 18 '18 at 09:14
3

You never actually try to copy or move the object, which is why you don't get an error.

The parameter Dummy &&obj is an rvalue reference parameter, meaning it can bind to rvalues but not to lvalues. It's still a reference, just like const Dummy &obj would be (which would also work in your case).

What std::move does is not to move anything, it casts its parameter to an rvalue reference. This makes it possible to pass it to functions expecting an rvalue (for example, a move constructor). For more details have a look at the answer linked by StoryTeller.

Pezo
  • 1,406
  • 9
  • 14