Returning member unique_ptr from class method - c++

I am trying to return a std::unique_ptr class member (trying to move the ownership) to the caller. The following is a sample code snippet:
class A {
public:
A() : p {new int{10}} {}
static std::unique_ptr<int> Foo(A &a) {
return a.p; // ERROR: Copy constructor getting invoked
// return std::move(a.p); WORKS FINE
}
std::unique_ptr<int> p;
};
I thought the compiler (gcc-5.2.1) would be able to do return value optimization (copy elision) in this case without requiring the explicit intent via std::move(). But that isn't the case. Why not?
The following code seems to be working fine, which seems equivalent:
std::unique_ptr<int> foo() {
std::unique_ptr<int> p {new int{10}};
return p;
}

The rule in [class.copy] is:
[...] when the expression in a return statement is a (possibly
parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression, overload resolution to
select the constructor for the copy is first performed as if the object were designated by an rvalue.
In this example:
std::unique_ptr<int> foo() {
std::unique_ptr<int> p {new int{10}};
return p;
}
p is the name of an object with automatic storage duration declared in the body of the function. So rather than copying it into the return value, we first try to move it. That works fine.
But in this example:
static std::unique_ptr<int> Foo(A &a) {
return a.p;
}
that doesn't apply. a.p isn't the name of an object at all, so we don't try overload resolution as if it were an rvalue, we instead just do the normal thing: try to copy it. This fails, so you have to explicitly move() it.
That's the wording of the rule, but it might not answer your question. Why is this the rule? Basically - we're trying to be safe. If we're naming a local variable, it's always safe to move from it in a return statement. It will never be accessed again. Easy optimization, no possible downside. But in your original example, a isn't owned by this function, neither is a.p. It's not inherently safe to move from it, so the language won't try to do it automatically.

Copy elision can't apply (among other reasons) since a.p is a std::unique_ptr, which is uncopyable. And since a.p has a lifetime beyond the body of A::Foo(A&), it would be very surprising (as in, surprising to the person writing the code) if the compiler automatically tried to move from a.p, which would likely wreck the class invariants of a. It would work if you return std::move(a.p);, but that explicitly steals a.p.

Related

Scope of variable local to static method in C++

I was trying to create an instance of an object with private constructor. Is this method correct?
#include <iostream>
using namespace std;
class A{
int y;
A(int y=2):y(y){};
public:
A(const A &obj){
cout<<"copy Cotr is called"<<endl;
this->y=obj.y;
}
int* addr(){
int *a=&y;
return a;
}
static A create(int y1=2){
class A a(y1);
cout<<&a<<endl;
return a;
}
void print(){
cout<<y<<endl;
}
};
int main(){
A o1=A::create(1);
A o2=A::create(3);
cout<<&o1<<" "<<&o2<<endl;
return 0;
}
The output is:
0x7ffd20d2f280
0x7ffd20d2f284
0x7ffd20d2f280 0x7ffd20d2f284
In the above code, I fail to understand few points:
create() returns a value, so during assignment which take place in A o1=A::create(1);, copy constructor should be called but it isn't. why?
Is this some undefined behavior as the address of the object created in create() and in main() are same and the object in create() is local and goes out of scope after the function ends.
create() returns a value, so during assignment which take place in A o1=A::create(1);, copy constructor should be called but it isn't. why?
You have copy-elision (Demo) which is an optimization allowed by standard.
The object is directly constructed in final place and no copy/move is done.
Some copy-elisions is even mandatory in C++17. (half of them in your case).
Is this some undefined behavior as the address of the object created in create() and in main() are same and the object in create() is local and goes out of scope after the function ends.
With copy elision, as object is directly constructed in final place, there is indeed only one address, it is as-if the local variable of create was the one from main.
This:
A a = x();
is different than this:
A a;
a = x();
In the second case you have a copy, in the first you don't.
To answer your second question, the object created in create() is local all right, but then it's copied back to the caller (actually, moved). Since the stack frame is the same, the local address is the same. But when it's copied, you have two different objects.
Thanks for all the answers. Dug deep into it and now answering my own question.
For the learned:
This is major instance of copy elision in C++ 17.
Answer ends for you. For the one who still didn't understood:
This method has no errors and do not show any undefined behavior. Most of the compilers uses C++11 or C++17 these days which is well integrated with copy elision(copy omission).
create() returns a value, so during assignment which take place in A
o1=A::create(1);, copy constructor should be called but it isn't. why?
Copy constructor is not called as the return type is prvalue(pure rvalue) and the compiler optimizes the program in such a way that the return value is created directly into the storage where the function's return value would otherwise be copied or moved to. So, actually no move or copy takes place so no move/copy constructor is called. Even after the end of create() destructor too is not called.
Is this some undefined behavior as the address of the object created
in create() and in main() are same and the object in create() is local
and goes out of scope after the function ends.
So, even after the function create() ends, the object dont get pushed out of scope or the destructor for that object is not called. As the object is created in not in the create() but in the main() itself. It is not an undefined behavior but a major benefit of C++ as unnecessary pointers and functions need not to be declared or invoked. Here, NRVO takes place.
In a return statement, when the operand is the name of a
non-volatile object with automatic storage duration, which isn't a
function parameter or a catch clause parameter, and which is of the
same class type (ignoring cv-qualification) as the function return
type. This variant of copy elision is known as NRVO, "named return
value optimization".

Passing a movable object

Reading an answer in SO, he passed a vector with move. I thought the correct way is to pass it simple without using move:
class B
{
std::vector<T> data;
public:
B(std::vector<T> p) : data(std::move(p)) {}
^^^^^^^^^^^^
?
};
The second way is:
class B
{
std::vector<T> data;
public:
B(std::vector<T> p) : data(p) {}
};
Which one is correct?
The function argument is already taken by value, so a copy will already have been made. The local object p is unquestioningly yours and yours alone, so you can move from it unconditionally.
The beauty of taking the argument by value is that it works for both lvalues and rvalues: For lvalues you make a genuine copy, since there's nothing else you can do, but for rvalues the function argument itself can be constructed by moving, so there's only one expensive construction happening ever, and everything else is moved.
When you construct an object from an lvalue, it will be copied. When you construct an object from a non-const rvalue it can be moved (whether it will be moved depends on the class having a move constructor). In the context of your constructor, p is clearly a lvalue: it has a name. However, it is a local variable and about to go away, i.e., it is save to move from it: std::move(p) makes the object appear as if it is an rvalue: in this context, std::move()ing the value is the right way to go.
Note that the recommendations are different if you return an object: a local value returned in a return statement is automatically moved from. Using std::move() would just reinforce the statement but would also inhibit the possibility of eliding the copy/move entirely. In your constructor the copy/move cannot be elided because copy elision only works with temporary objects or with local objects in return statements.
T f() {
T local;
return local; // good: elided, moved, or copied in this order of preference
}
T g() {
T local;
return std::move(local); // bad: can't be elided and will be moved or copied
}

Why isn't object returned by std::move destroyed immediately

I tested the following code:
#include <iostream>
using namespace std;
class foo{
public:
foo() {cout<<"foo()"<<endl;}
~foo() {cout<<"~foo()"<<endl;}
};
int main()
{
foo f;
move(f);
cout<<"statement \"move(f);\" done."<<endl;
return 0;
}
The output was:
foo()
statement "move(f);" done.
~foo()
However, I expected:
foo()
~foo()
statement "move(f);" done.
According to the source code of the function move:
template<typename _Tp>
constexpr typename std::remove_reference<_Tp>::type&&
move(_Tp&& __t) noexcept
{ return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
The returned object is a right value, So Why isn't it destroyed immediately?
-----------------------------------------------------------------
I think I just confused rvalue and rvalue reference.
I modified my code:
#include <iostream>
template<typename _Tp>
constexpr typename /**/std::remove_reference<_Tp>::type /* no && */
/**/ mymove /**/ (_Tp&& __t) noexcept
{ return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
using namespace std;
class foo{
public:
foo() {cout<<"foo() at "<<this<<endl;} /* use address to trace different objects */
~foo() {cout<<"~foo() at "<<this<<endl;} /* use address to trace different objects */
};
int main()
{
foo f;
mymove(f);
cout<<"statement \"mymove(f);\" done."<<endl;
return 0;
}
And now I get what I've been expecting:
foo() at 0x22fefe
~foo() at 0x22feff
statement "mymove(f);" done.
~foo() at 0x22fefe
Moving from an object doesn't change its lifetime, only its current value. Your object foo is destroyed on return from main, which is after your output.
Futhermore, std::move doesn't move from the object. It just returns an rvalue reference whose referand is the object, making it possible to move from the object.
Objects get destroyed when they go out of scope. Moving from an object doesn't change that; depending on what the move constructor or move assignment operator does, the state of the object can be different after the move, but is hasn't yet been destroyed, so the practical rule is that moving from an object must leave it in a state that can be destroyed.
Beyond that, as #R.MartinhoFernandes points out, std::move doesn't do anything. It's the object's move constructor or move assignment operator that does whatever needs to be done, and that isn't applied in a call to std::move; it's applied when the moved-from object is used to construct a new object (move constructor) or is assigned to an existing object (move assignment operator). Like this:
foo f;
foo f1(f); // applies foo's copy constructor
foo f2(std::move(f)); // applies foo's move constructor
foo f3, f4;
f3 = f; // applies foo's copy assignment operator
f4 = std::move(f1); // applies foo's move assignment operator
A std::move doesn't change objects lifetime. Roughly speaking it's nothing more than a static_cast that casts a non const lvalue to a non const rvalue reference.
The usefulness of this is overload resolution. Indeed, some functions take parameters by const lvalue reference (e.g. copy constructors) and other take by non const rvalue reference (e.g. move constructors). If the passed object is a temporary, then the compiler calls the second overload. The idea is that just after the function is called the a temporary can no longer be used (and will be destroyed). Therefore the second overload could take ownership of the temporary's resources instead of coping them.
However, the compiler will not do it for a non-temporary object (or, to be more correct for an lvalue). The reason is that the passed object has a name that remains in scope and therefore is alive could still be used (as your code demonstrate). So its internal resources might still be required and it would be a problem if they have had been moved to the other object. Nevertheless, you can instruct the compiler that it can call the second overload by using std::move. It casts the argument to a rvalue reference and, by overload resolution, the second overload is called.
The slight changed code below illustrate this point.
#include <iostream>
using namespace std;
class foo{
public:
foo() { cout << "foo()" << endl; }
~foo() { cout << "~foo()" << endl; }
};
void g(const foo&) { cout << "lref" << endl; }
void g(foo&&) { cout << "rref" << endl; }
int main()
{
foo f;
g(f);
g(move(f));
// f is still in scope and can be referenced.
// For instance, we can call g(f) again.
// Imagine what would happen if f had been destroyed as the question's author
// originally though?
g(static_cast<foo&&>(f)); // This is equivalent to the previous line
cout<<"statement \"move(f);\" done."<<endl;
return 0;
}
The output is
foo()
lref
rref
rref
statement "move(f);" done.
~foo()
Update: (After the question has been changed to use mymove)
Notice that the new code doesn't give exactly what you said at the very beginning. Indeed it reports two calls to ~foo() rather than one.
From the displayed addresses we can see that the original object of type foo, namely, f is destroyed at the very end. Exactly as it used to be with the original code. As many have pointed out, f is destroyed only at the end of its scope (the body of function main). This is still the case.
The extra call to ~foo() reported just before the statement "mymove(f);" done. destroys another object which is a copy of f. If you add a reporting copy constructor to foo:
foo(const foo& orig) { cout << "copy foo from " << &orig << " to " << this << endl;}
Then you get an output similar to:
foo() at 0xa74203de
copy foo from 0xa74203de to 0xa74203df
~foo() at 0xa74203df
statement "move(f);" done.
~foo() at 0xa74203de
We can deduce that calling mymove yields a call to the copy constructor to copy f to another foo object. Then, this newly created object is destroyed before execution reaches the line that displays statement "move(f);" done.
The natural question now is where this copy come from? Well, notice the return type of mymove:
constexpr typename /**/std::remove_reference<_Tp>::type /* no && */`
In this example, after a simplification for clarity, this boils down to foo. That is, mymove returns a foo by value. Therefore, a copy is made to create a temporary object. As I said before, a temporary is destroyed just after the expression that creates it finishes to be evaluated (well, there are exceptions to this rule but they don't apply to this code). That explains the extra call to ~foo().
Because in the general case, the move could happen in another translation unit. In your example, the object wasn't even moved, only marked as movable. This means that the caller of std::move will not know if the object was moved or not, all he knows is, that there is an object and that it has to call the destructor at the end of the scope/lifetime of that object. std::move only marks the object as movable, it does not perform the move operation or create a moved copy that can be further moved or anything like that.
Consider:
// translation unit 1
void f( std::vector< int >&& v )
{
if( v.size() > 8 ) {
// move it
}
else {
// copy it as it's just a few entries
}
}
// translation unit 2
void f( std::vector< int >&& );
std::vector< int > g();
int main()
{
// v is created here
std::vector< int > v = g();
// it is maybe moved here
f( std::move( v ) );
// here, v still exists as an object
// when main() ends, it will be destroyed
}
In the example above, how would translation unit 2 decide whether or not to call the destructor after the std::move?
You're getting confused by the name -- std::move doesn't actually move anything. It just converts (casts) an lvalue reference into an rvalue reference, and is used to make someone else move something.
Where std::move is useful is when you have an overloaded function that takes either an lvalue or an rvalue reference. If you call such a function with a simple variable, overload resolution means you'll call the version with the lvalue reference. You can add an explicit call to std::move to instead call the rvalue reference version. No moves involved, except within the function that takes the rvalue reference.
Now the reason it is called move is the common usage where you have two constructors, one of which takes an lvalue reference (commonly called the copy constructor) and one that takes an rvalue reference (commonly called the move constructor). In this case, adding an explicit call to std::move means you call the move constructor instead of the copy constructor.
In the more general case, it's common practice to have overloaded functions that take lvalue/rvalue references where the lvalue version makes a copy of the object and the rvalue version moves the object (implicitly modifying the source object to take over any memory it uses).
Suppose code like this:
void bar(Foo& a) {
if (a.noLongerneeded())
lastUnneeded = std::move(a);
}
In this case, the caller of bar can not know that the function might in some cases end up calling the destructor of the passed object. It will feel responsible for that object, and make sure to call its destructor at any later point.
So the rule is that move may turn a valid object into a different but still valid object. Still valid means that calling methods or the destructor on that object should still yield well-defined results. Strictly speaking, move by itself does nothing except tell the receiver of such a reference that it may change the object if doing so makes sense. So it's the recipient, e.g. move constructor or move assignment operator, which does the actual moving. These operations will usually either not change the object at all, or set some pointers to nullptr, or some lengths to zero or something like that. They will however never call the destructor, since that task is left to the owner of the object.

What is the rationale for not allowing temporaries bound to references in initialization lists to live past end of ctor?

Simple example:
struct A
{
A() : i(int()) {}
const int& i;
};
Error from gcc:
a temporary bound to 'A::i' only persists until the constructor exits
Rule from 12.2p5:
A temporary bound to a reference member in a constructor’s
ctor-initializer (12.6.2) persists until the constructor exits.
Question
Does anybody know the rationale for this rule? It would seem to me that allowing the temporary to live until reference dies would be better.
I don't think the not extending to the object lifetime needs justification. The opposite would!
The lifetime extension of a temporary extends merely to the enclosing scope, which is both natural and useful. This is because we have tight control on the lifetime of the receiving reference variable. By contrast, the class member isn't really "in scope" at all. Imagine this:
int foo();
struct Bar
{
Bar(int const &, int const &, int const &) : /* bind */ { }
int & a, & b, & c;
};
Bar * p = new Bar(foo(), foo(), foo());
It'd be nigh impossible to define a meaningful lifetime extension for the foo() temporaries.
Instead, we have the default behaviour that the lifetime of the foo() temporary extends to the end of the full-expression in which it is contained, and no further.
The int() in your constructor initialization list is on the stack.
Once that value is set, int() goes out of the scope and the reference becomes invalid.
What memory would it live in?
For it to work the way you propose, it can't be on the stack since it has to live longer than any single function call. It can't be put after struct A in memory, because it would have no way to know how A was allocated.
At best, it would have to be turned into a secret heap allocation. That would then require a corresponding secret deallocation when the destructor runs. The copy constructor and assignment operator would need secret behavior too.
I don't know if anyone ever actually considered such a way of doing it. But personally, it sounds like too much extra complexity for a rather obscure feature.

Can we return objects having a deleted/private copy/move constructor by value from a function?

In C++03 it is impossible to return an object of a class having a private non-defined copy constructor by value:
struct A { A(int x) { ... } private: A(A const&); };
A f() {
return A(10); // error!
return 10; // error too!
}
I was wondering, was this restriction lifted in C++11, making it possible to write functions having a class type return type for classes without constructors used for copy or move? I remember it could be useful to allow callers of a function use the newly returned object, but that they are not able to copy the value and store it somewhere.
Here is how it can work
A f() {
return { 10 };
}
This works even though A has no working copy or move constructor and no other constructor that could copy or move an A!
To make use of this feature of C++11, the constructor (taking int in this case) has to be non-explicit though.
The restriction has not been lifted. As per the access specifier, there is a note in §12.8/32 that explains:
two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided.
As of the deleted copy/move constructors §8.4.3/2 states that
A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed. [ Note: This includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member to the function. It applies even for references in expressions that are not potentially-evaluated. If a function is overloaded, it is referenced only if the function is selected by overload resolution. — end note ]
Not sure about this particular case, but my understanding of the quote is that, if after the overload resolution in §12.8/32 the deleted copy/move constructor is selected, even if the operation is elided, that could constitute a reference to the function, and the program would be ill formed.
The above code is still ill-formed in C++11. But you could add a public move constructor to A and then it would be legal:
struct A
{
A(int x) {}
A(A&&);
private:
A(A const&);
};
A f() {
return A(10); // Ok!
}
I was wondering, was this restriction lifted in C++11?
How could it be? By returning something by value, you are by definition copying (or moving) it. And while C++ can allow that copy/move to be elided in certain circumstances, it's still copying (or moving) by the specification.
I remember it could be useful to allow callers of a function use the returned object, but that they are not able to copy the value and store it somewhere.
Yes. You get rid of the copy constructor/assignment, but allow the value to be moved. std::unique_ptr does this.
You can return a unique_ptr by value. But in doing so, you are returning an "prvalue": a temporary that is being destroyed. Therefore, if you have a function g as such:
std::unique_ptr<SomeType> g() {...}
You can do this:
std::unique_ptr<SomeType> value = g();
But not this:
std::unique_ptr<SomeType> value1 = g();
std::unique_ptr<SomeType> value2 = g();
value1 = value 2;
But this is possible:
std::unique_ptr<SomeType> value = g();
value = g();
The second line invokes the move assignment operator on value. It will delete the old pointer and move the new pointer into it, leaving the old value empty.
In this way, you can ensure that the contents of any unique_ptr is only ever stored in one place. You can't stop them from referencing it in multiple places (via pointers to unique_ptr or whatever), but there will be at most one location in memory where the actual pointer is stored.
Removing both the copy and move constructors creates an immobile object. Where it is created is where it's values stay, forever. Movement allows you to have unique ownership, but without being immobile.
You could probably hack together a proxy to do the trick if you really wanted, and have a converting constructor that copies the value stored within the proxy.
Something along the lines of:
template<typename T>
struct ReturnProxy {
//This could be made private, provided appropriate frienship is granted
ReturnProxy(T* p_) : p(p_) { }
ReturnProxy(ReturnProxy&&) = default;
private:
//don't want these Proxies sticking around...
ReturnProxy(const ReturnProxy&) = delete;
void operator =(const ReturnProxy&) = delete;
void operator =(ReturnProxy&&) = delete;
struct SUPER_FRIENDS { typedef T GO; };
friend struct SUPER_FRIENDS::GO;
unique_ptr<T> p;
};
struct Object {
Object() : data(0) { }
//Pseudo-copy constructor
Object(ReturnProxy<Object>&& proxy)
: data(proxy.p ? proxy.p->data : throw "Don't get sneaky with me \\glare")
{
//steals `proxy.p` so that there isn't a second copy of this object floating around
//shouldn't be necessary, but some men just want to watch the world burn.
unique_ptr<Object> thief(std::move(proxy.p));
}
private:
int data;
Object(const Object&) = delete;
void operator =(const Object&) = delete;
};
ReturnProxy<Object> func() {
return ReturnProxy(new Object);
}
int main() {
Object o(func());
}
You could probably do the same in 03, though, using auto_ptrs. And it obviously doesn't prevent storage of the resultant Object, although it does limit you to one copy per instance.