24

Possible Duplicate:
Returning unique_ptr from functions

20.7.1.2 [unique.ptr.single] defines copy constructor like this :

// disable copy from lvalue
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;

So, why the following code compiles fine?

#include <memory>
#include <iostream>

std::unique_ptr< int > bar()
{
  std::unique_ptr< int > p( new int(4));
  return p;
}

int main()
{
  auto p = bar();

  std::cout<<*p<<std::endl;
}

I compiled it like this :

g++ -O3  -Wall -Wextra -pedantic -std=c++0x kel.cpp

The compiler : g++ version 4.6.1 20110908 (Red Hat 4.6.1-9)

Community
  • 1
  • 1
BЈовић
  • 57,268
  • 38
  • 158
  • 253

3 Answers3

45

In the return statement, if you return a local variable, the expression is treated as an rvalue, and thus automatically moved. It is thus similar to:

  return std::move(p);

It invokes the unique_ptr(unique_ptr&&) constructor.

In the main function, bar() produces a temporary, which is an rvalue, and is also properly moved into the p in main.

R. Martinho Fernandes
  • 209,766
  • 68
  • 412
  • 492
  • No, subobjects are not automatically moved. – Xeo Mar 22 '12 at 17:24
  • 12.8/31 has the exact example as in my question. Both you and Nawaz are right – BЈовић Mar 22 '12 at 17:55
  • @Xeo you're right. Wasn't there a question about that around? Yup, there is http://stackoverflow.com/questions/9183087/will-member-subobjects-of-local-variables-be-moved-too-if-returned-from-a-functi – R. Martinho Fernandes Mar 22 '12 at 18:03
  • 4
    "*It is thus the same as: `return std::move(p);`*" Almost -- doesn't the latter inhibit (N)RVO? – ildjarn Mar 22 '12 at 18:25
  • @ildjarn Hmm, maybe. The standard wording describes it something like "when the criteria for copy elision are met, and it is an lvalue, it is treated as an rvalue for overload resolution." I don't know if that affects that. I'll reword anyway. – R. Martinho Fernandes Mar 22 '12 at 18:30
  • a local variable with a name is an lvalue, which is magically treated here as rvalue? never heard of that – Gabriel Oct 07 '15 at 20:11
  • Note that it is similar but not equivalent. An implicit move prevents copy elision. – ManuelSchneid3r Oct 13 '17 at 09:35
16

It is not copied, it is moved.

The return statement is equivalent to this:

return std::move(p);

Pedantically speaking, that is semantically equivalent. In reality, the compiler may optimize the code, eliding the call to the move-constructor. But that is possible only if you write it as:

return p; //It gives the compiler an opportunity to optimize this. 

That is recommended. However, the compiler has no opportunity to optimize if you write this:

return std::move(p); //No (or less) opportunity to optimize this. 

That is not recommended. :-)

Nawaz
  • 327,095
  • 105
  • 629
  • 812
1

I think that copying from an lvalue is disabled, but "bar()" is an rvalue so it's OK. You definitely need to be able to copy from rvalues.

David Grayson
  • 71,301
  • 23
  • 136
  • 171