-3

Hi I am putting my hands on C++11 and there is a behavior I am not able to understand:

std::unique_ptr<int> foo()
{
  std::unique_ptr<int> p(new int(3));
  return p; //1
}
int main()
{
  std::unique_ptr<int> p2 = foo(); //2
}

Compile

std::unique_ptr<int> p(new int(3));

std::unique_ptr<int> foo()
{
  return p;
}

int main()
{
  std::unique_ptr<int> p2 = foo(); //2
}

Don't compile saying that I am trying to use a deleted operation (probably copy), but both //1 and //2 are making copy of the object which is not allowed.

I read the standard:

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object […] This elision of copy/move operations, called copy elision, is permitted […] in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object with the same cv-unqualified type as the function return type […]

But it is not really clear to me. Thanks for your help.

Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
user1594047
  • 181
  • 1
  • 1
  • 12
  • //1 can't compile, what compiler are you using ? You can `return std::move(p);` when it makes sense to move, and it often is when dealing with unique_ptr – quantdev Jan 19 '15 at 04:39
  • What isn't clear? `unique_ptr` can't be copied, both `return p` and initialising `p2` with `p` attempt to make a copy. – user657267 Jan 19 '15 at 04:43
  • Are you surprised by the fact that you *do* or *do not* get an error? – 5gon12eder Jan 19 '15 at 04:43
  • @quantdev Of course //1 complies, `p` is treated as if it were an rvalue and moved, you don't need `std::move(p);`. See [this](http://stackoverflow.com/questions/4316727/returning-unique-ptr-from-functions). //2 doesn't because `p2` is being copy initialized from `p` which requires an accessible copy constructor. Change it to direct initialization and it'll work `std::unique_ptr p2{p};` – Praetorian Jan 19 '15 at 04:45
  • 4
    @Praetorian: Unless the OP is misrepresenting his code, `p` is a global variable. It cannot be automatically moved. – Benjamin Lindley Jan 19 '15 at 04:47
  • @Praetorian : OP example is [this](http://coliru.stacked-crooked.com/a/1fac182107494589), returning from a global, which is the subtlety here – quantdev Jan 19 '15 at 04:47
  • so for that to works the variable copy need to be created in the function that returns it ? – user1594047 Jan 19 '15 at 04:47
  • 1
    @quantdev Oops, missed that `p` is a global variable. Yeah, it shouldn't compile – Praetorian Jan 19 '15 at 04:48
  • 2
    Doesn't compile for me on VS2103 `error C2280: 'std::unique_ptr>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference a deleted function` – Praetorian Jan 19 '15 at 04:50
  • yep I made a mistake the first case is compiling, the first case should not be using the global variable. And this is what I don't understand, why in one case it is working and not in the other one. – user1594047 Jan 19 '15 at 04:54
  • 3
    You know, most text editors include a nifty "copy" feature, that allows you to store text verbatim in memory provided by your OS. And most web browsers have a corresponding "paste" feature which allows you to retrieve that text. – Benjamin Lindley Jan 19 '15 at 05:02
  • @user1594047 I accidentally answered your current question in my first comment by not reading the question as it was posted then closely enough. I once asked the same question a long time ago, and it is answered [here](http://stackoverflow.com/questions/4316727/returning-unique-ptr-from-functions). – Praetorian Jan 19 '15 at 05:20

1 Answers1

3

As the current questions stands, both lines 1 and 2, should not compile because they are trying to make a copy of a non-copyable type. It is currently unclear if this is what you are seeing and questioning, or if this is what you are not seeing, and questioning.

If either lines 1 or 2 compile for you, this is a bug in your compiler or std::lib.

update

Now there is a new and different question.

And the new question claims that this compiles:

std::unique_ptr<int> foo()
{
std::unique_ptr<int> p(new int(3));
return p; //1
}
int main()
{
std::unique_ptr<int> p2 = p; //2
}

It does not compile for me. The first error is:

error: use of undeclared identifier 'std'

If I #include <memory>, then the next error is:

test.cpp:10:27: error: use of undeclared identifier 'p'
std::unique_ptr<int> p2 = p; //2
                          ^

If you are not seeing these errors, your compiler/library is buggy.

update 2

Now there is a third question:

This does compile for me:

#include <memory>

std::unique_ptr<int> foo()
{
std::unique_ptr<int> p(new int(3));
return p; //1
}
int main()
{
std::unique_ptr<int> p2 = foo(); //2
}

(I had to add #include <memory> to get it to compile)

But this correctly does not compile:

#include <memory>

std::unique_ptr<int> p(new int(3));

std::unique_ptr<int> foo()
{
return p;
}

int main()
{
std::unique_ptr<int> p2 = foo(); //2
}

The latter error is on the unmarked line above:

return p;

This is an error because it attempts to make a copy of p which is not a copyable type.

The line marked //2 is not an error because it is not trying to make a copy of the prvalue returned by foo(). It is instead move constructing the value return by foo(), and this is using a moveable type.

There are many, many references available online about move semantics. Here is one, although it is dated. But it is simple and gets the basics of the ideas across.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • I have modified my question you were right I made a mistake for case1, should not have use the global variable in the first case – user1594047 Jan 19 '15 at 04:51
  • My bad so many errors in my code, I just fix them, I can summarize my question by : what is the difference if the variable returned is declared inside the function or outside. – user1594047 Jan 19 '15 at 05:01
  • So the error is coming from return p ? because visual studio tells me it comes from //2 – user1594047 Jan 19 '15 at 05:30