3

I am new to c++11 and trying to understand to meaning of std::move and unique_ptr and wrote the following code, which I use std::move on a unique_ptr in two different ways:

void unique_ptr_plain_move() {
  unique_ptr<int> intptr(new int(10));
  unique_ptr<int> intptr2;

  printf("*intptr = %d\n", *intptr);
  intptr2 = std::move(intptr);
  printf("*intptr2 = %d\n", *intptr2);
  // as expected, crash here as we have already moved intptr's ownership.
  printf("*intptr = %d\n", *intptr);
}

/////////////////////////////////////////////

void function_call_move(unique_ptr<int>&& intptr) {
  printf("[func] *intptr = %d\n", *intptr);
}

void unique_ptr_function_call_move() {
  unique_ptr<int> intptr(new int(10));

  printf("*intptr = %d\n", *intptr);
  function_call_move(std::move(intptr));
  // this does not crash, intptr still has the ownership of its pointed instance ....
  printf("*intptr = %d\n", *intptr);
}

In unique_ptr_plain_move(), intptr2 takes the ownership of intptr after std::move and therefore we can no longer use intptr. However, in unique_ptr_function_call_move(), when using std::move in a function call, intptr still have its ownership of its pointed instance. Can I know what exactly happened when we pass a std::move(unique_ptr) to a function? Thank you.

keelar
  • 5,334
  • 6
  • 35
  • 73
  • A call to `std::move` doesn't by itself move anything. It just allows other functions that want to steal contents of the object to do so. `function_call_move` is not such a function. – Igor Tandetnik Feb 03 '14 at 21:24
  • 4
    std::move creates a RValue Reference from unique_ptr. function_call_move takes a RValue Reference, but until a RValue Reference assignment operator or constructor is used to steal the unique_ptr's information it doesn't get harmed. Essentially just because you *can* mug it and steal it's info doesn't mean you have to. – Dan Feb 03 '14 at 21:25
  • @Dan: thank you very much for your comment. So it is the `=` operation does the ownership transfer, not the `std::move`, am I right at this part? – keelar Feb 03 '14 at 21:28
  • 2
    See [Why is `std::move` named `std::move`?](http://stackoverflow.com/questions/21358432/why-is-stdmove-named-stdmove) – dyp Feb 03 '14 at 21:34

1 Answers1

5

The key concept here is that std::move by itself won't do any moving. You can think of it as marking the object as a object that can be moved from.

The signature for function_call_move is

void function_call_move( unique_ptr<int>&& ptr );

Which means it can only receive objects that could be moved from, formally known as rvalues, and bind that to a reference. The act of associating an rvalue to a rvalue reference don't invalidate the state of the original object either.

So, unless function_call_move actually moves ptr to another std::unique_ptrinside it, your call to function_call_move(std::move(intptr)); won't invalidate intptr and your usage will be perfectly fine.

Tiago Gomes
  • 386
  • 2
  • 7
  • 1
    I'm sorry that I didn't provide the signature for `function_call_move` at the very beginning, but I have provided right after I observed that. Thank you very much for your detailed answer! – keelar Feb 03 '14 at 21:29