Reputation: 2489
I have few questions regarding the following example:
unique_ptr<A> foo(){
unique_ptr<A> a = make_unique<A>(5);
return move(a);
}
unique_ptr<A>&& foo(){
unique_ptr<A> a = make_unique<A>(5);
return move(a);
}
unique_ptr<int> foo(){
unique_ptr<int> a = make_unique<int>(5);
return a;
}
First example:
Why does the compiler allow such thing? Aren't we returning a rvalue ref? Why does the compiler allow such an implicit cast? Who holds the underlying object? And who is responsible to destroy it at the end?
Second example:
When I'm doing it, I get garbage from the return type of the function. While I thought this is the "right" way to do this, aren't we declaring we are returning a rval ref, and actually moving our object as such?
Third example:
If the copy constructor of a unique_ptr
is deleted, what happens here that allows this function? a
is a unique_ptr
, and we are returning it by value, so won't that create a copy?
Upvotes: 2
Views: 467
Reputation: 154015
Here is a quick run-down:
The first example is kind of OK but the std::move(a)
inhibits cooy-elision. Sure, moves are better than copies but no work is, yet, better.
An rvalue reference is still a reference and you’ll need to keep the referenced object alive. Before the returned reference can be accessed the local object referenced is destroyed. It is rarely useful to return rvalue references although some standard functions do so (std::move(x)
, std::forward<T>(x)
, std::declval<T>()
) but for these there is a non-local object returned.
When copy elision is possible, the objects are implicitly moved. That’s the way to go as copy elision remains viable.
It seems you are unaware of copy elision: in some situations where a copy is needed the compiler is allowed to elide the copy even if the semantics of the program are changed (i.e., the side effect of the copy ctor and the dtor don’t happen). Effectively, copy elision allows the object to be constructed in the correct location straight away. There are just a few cases when copy elision is permitted (the exact rules are more complicated):
Since no copy is done in these cases as the object is already in the correct location it seemed reasonable to extend the rules to move operations: when copy elision is permitted, the object is implicitly moved. The net effect is that it is sufficient to have either a copy or a move constructor. Any decent compiler will neither copy nor move but elide the copy/move construction.
Upvotes: 4