By Alex

2014-09-17 07:49:23 8 Comments

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?


@rodrigo 2014-09-17 07:56:25

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


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!!!

@M.M 2014-09-17 08:00:22

This isn't generally true. It only applies in the situation where p qualifies for copy elision.

@rodrigo 2014-09-17 08:01:57

@MattMcNabb: Which is on every return expression with value. And a few other places.

@juanchopanza 2014-09-17 08:03:24

@rodrigo No, it isn't that simple. The conditions for copy elision are more complicated than that (unfortunately!)

@M.M 2014-09-17 08:03:58

@rodrigo " in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value" .

@rodrigo 2014-09-17 08:04:16

@MattMcNabb & juanchopanza: Oh! You both are right! A return of a global variable will not qualify for copy elision, for example.

@juanchopanza 2014-09-17 08:06:05

@rodrigo Other examples: a function parameter, or something inside an if statement.

@juanchopanza 2014-09-17 08:14:44

i.e your answer is still wrong.

@rodrigo 2014-09-17 08:27:21

@juanchopanza: Fair enough. I've rephrased it. In this answer I prefer to avoid excessive technical terms or too much details.

@juanchopanza 2014-09-17 07:58:16

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.)

Related Questions

Sponsored Content

7 Answered Questions

[SOLVED] What is std::move(), and when should it be used?

8 Answered Questions

[SOLVED] How to convert a std::string to const char* or char*?

  • 2008-12-07 19:30:56
  • user37875
  • 926199 View
  • 891 Score
  • 8 Answer
  • Tags:   c++ string char const

19 Answered Questions

[SOLVED] How can I profile C++ code running on Linux?

  • 2008-12-17 20:29:24
  • Gabriel Isenberg
  • 522074 View
  • 1812 Score
  • 19 Answer
  • Tags:   c++ linux profiling

6 Answered Questions

1 Answered Questions

[SOLVED] Return std::tuple and move semantics / copy elision

5 Answered Questions

[SOLVED] Returning unique_ptr from functions

  • 2010-11-30 17:44:37
  • Praetorian
  • 157792 View
  • 362 Score
  • 5 Answer
  • Tags:   c++ c++11 unique-ptr

1 Answered Questions

[SOLVED] Can't move a std::unique_lock into a struct

Sponsored Content