Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can a unique_ptr be returned by value without std::move? [duplicate]

std::unique_ptr<int> ptr() {
    std::unique_ptr<int> p(new int(3));
    return p;  //  Why doesn't this require explicit move using std::move?
}  // Why didn't the data pointed to by 'p' is not destroyed here though p is not moved?

int main() {
    std::unique_ptr<int> a = ptr();  // Why doesn't this require std::move? 
    std::cout << *a; // Prints 3.
}

In the above code, the function ptr() returns a copy of p. When p goes out of scope, the data '3' should get deleted. But how does the code work without any access violation?

like image 847
Alex Avatar asked Sep 17 '14 07:09

Alex


People also ask

Can you pass unique_ptr by value?

Because the unique pointer does not have a copy constructor. Hence you cannot pass it by value, because passing by value requires making a copy. Actually that is nearly the sole and whole point of a unique_ptr .

Can I return std :: unique_ptr from a function?

If a function returns a std::unique_ptr<> , that means the caller takes ownership of the returned object.

Can you move a unique_ptr?

A unique_ptr can only be moved. This means that the ownership of the memory resource is transferred to another unique_ptr and the original unique_ptr no longer owns it. We recommend that you restrict an object to one owner, because multiple ownership adds complexity to the program logic.

What happens when unique_ptr goes out of scope?

unique_ptr. An​ unique_ptr has exclusive ownership of the object it points to and ​will destroy the object when the pointer goes out of scope.


2 Answers

This is set out in the C++11 standard, § 12.8/32:

When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue....

(emphasis mine). In plain english, it means that the lvalue p can be treated as an rvalue when it comes to overload resolution, because it is a candidate for copy elision. This in turn means the move constructor is picked up on overload resolution (in actual fact, the move copy is probably elided anyway.)

like image 128
juanchopanza Avatar answered Oct 20 '22 11:10

juanchopanza


Because return of certain expressions, such as local automatic variables, are explicitly defined to return a moved object, if the moving operator is available.

So:

return p;

is more or less similar to:

return std::move(p);

But note that this will not work for example with a global variable.

std::unique_ptr<int> g(new int(3));
std::unique_ptr<int> ptr() {
    return g;  //  error!!!
}
like image 6
rodrigo Avatar answered Oct 20 '22 10:10

rodrigo