Is return value always a temporary? - c++

This page says a strange thing :-
The temporaries are created only if your program does not copy the return value to an object and example given is
UDT Func1(); // Declare a function that returns a user-defined type.
...
Func1(); // Call Func1, but discard return value.
// A temporary object is created to store the return
// value
but if i have done :-
UDT obj=Fuct1;
It appears to me that it will also create a temporary as follow:-
Func() constructs a local object. Next, this local object is copy-constructed on the caller's stack, making a temporary object that is used as the argument of obj's copy-constructor.
Am I wrong?
Is this has something to do with copy elision?

The page you cite it a description of the behavior of a specific
compiler. Formally: the return value is always a temporary. In
contexts where that temporary is used as the argument of a copy
constructor (the object is copied), the standard gives explicit
authorization for the compiler to elide the copy, “merging”
the temporary with the named variable it is initializing. All the
sentence you quote is saying is that this specific compiler always does
his optimization (as do most other compilers).

This page is Microsoft specific. It's true that the standard permits to do two, one or zero calls to the copy constructor during function return (this is called copy elision). In fact one call is always sufficient.
Suppose you write:
A f(int x) {
return A(x);
}
void g() {
A r = f(10);
}
The way MSVC implements this is:
void f_impl(A* r, int x) {
new((void*)r) A(x); // construct the return value into r
}
void g_impl() {
A r = __uninitialized__;
f_impl(&r, 10);
}
Here you see zero calls to the copy constructor and no temporaries.
If you call f like this:
void g() {
f(10);
}
Then the compiler still needs to construct the return value somewhere, so it creates a temporary:
void g_impl() {
A r = __uninitialized__;
f_impl(&r, 10);
r.~A(); // destruct temporary
}
When it calls the copy constructor? In the implementation of f when it can't know which f's local will be returned. E.g. this:
A f(int x)
{
A r1;
A r2;
// ...do something complicated modifying both r1 and r2...
if(x)
return r1;
// ...do something complicated...
return r2;
}
Is translated to something like this:
void f_impl(A* r, int x)
{
A r1;
A r2;
// ...do something complicated modifying both r1 and r2...
if(x)
{
new((void*)r) A(r1); // copy construct r1
return;
}
// ...do something complicated...
new((void*)r) A(r2); // copy construct r2
}

The return value is always a temporary. In the second case, a copy of that temporary (move in C++11) is made if copy elision cannot occur.

Related

Returning Eigen matrices and temporaries

Consider the following function Foo:
// ...
Eigen::Vector3d Foo() {
Eigen::Vector3d res;
// ...
return res;
}
int main () {
Eigen::VectorXd foo = Foo(); // (1)
return 0;
}
The line (1) should not create any temporaries due to return value optimization. But consider the following case:
// ...
int main () {
Eigen::VectorXd foo;
// ...
foo.head<3>() = Foo(); // (2)
return 0;
}
Does (2) create any temporaries? More generally, does initializing any block of a matrix as in (2) create any temporaries? It would be great if this were not the case. Otherwise, I could redefine Foo as follows:
// ...
void AlternativeFoo(Eigen::Ref<Eigen::Vector3d> res) {
// Modify res
}
int main () {
Eigen::VectorXd foo;
// ...
AlternativeFoo(foo.head<3>()); // (3)
return 0;
}
Is (3) the only way to achieve the above without creating temporaries?
The line (1) should not create any temporaries due to return value optimization.
No, it must materialize a temporary for the return value of Foo.
The return type of Foo and the type of the variable foo do not match (up to cv-qualification): Vector3d vs VectorXd.
But this is a necessary condition for copy elision to be allowed.
If that is not the case, the constructor used will be neither a copy nor a move constructor in the first place.
So elision doesn't happen and in the constructor that is going to be called, the return value of Foo is bound to a reference argument, which will cause materialization of the temporary.
Does (2) create any temporaries? More generally, does initializing any block of a matrix as in (2) create any temporaries?
Yes, again temporaries for the Foo return values will be materialized, this time caused by binding to reference parameters in the operator=.
Is (3) the only way to achieve the above without creating temporaries?
I would assume so, but it probably doesn't matter anyway.
Assuming Foo can be inlined, the distinction is likely going to become meaningless and the compiler will figure out if the operations in Foo can be performed directly on the storage of foo or not.
If Foo cannot be inlined, then copying the three entries of the vector is unlikely to have significant relevance against the function call. Your alternative solution would in this case force extra indirection, which may be more costly than copying a few values as well.

Returning object from function using constructor

Example class:
class myclass
{
int a;
int b;
public:
myclass() {}
myclass(int x, int y)
{
a = x;
b = y;
}
};
Function:
myclass function()
{
return myclass(2, 3);
}
This line I do not understand:
return myclass(2, 3);
How is it possible to return object like this?
Looks like copy constructor is being used but constructors shouldn't return any value? (c++ beginner language please)
The return statement has a specific syntax: return expression where expression is convertible to the function return type.
So myclass(2, 3) is convertible to the return type (it is the same type). You could also have used return {2,3};.
From the link we also note:
Returning by value may involve construction and copy/move of a
temporary object, unless copy elision is used.
The statement
return myclass(2, 3);
does two things:
First a temporary object is created. This is what myclass(2, 3) does. It creates an object, calling the appropriate constructor.
The temporary object is returned, by value which means it's copied (or more likely the copy is elided as part of return value optimizations).
myclass(2, 3) is an expression that evaluates to a new (temporary) object of type myclass, constructed by invoking the myclass::myclass(int, int) constructor.
return myclass(2, 3); uses the value of such expression (the newly constructed myclass) as return value of function function. This in turn possibly invokes a copy constructor to copy the value from the temporary location where it has been constructed to whatever location is used for the return value (unless RVO kicks in, which should be mandatory in some recent C++ standard).

Can returning a braced enclosed initializer lead to a copy in C++?

Example:
struct s { int a; };
s func() { return {42}; }
int main() {
s new_obj = func(); // line 6
(void) new_obj;
return 0;
}
This works. Now, what happens, if we assume that our compiler does no RVO?
func returns a struct of s, so {42} must be converted to s, is then returned and finally copied to new_obj in line 6.
func returns an initializer list, so a deep copy is impossible.
What does the language say? Can you give a proof?
Note: I know that this does not seem useful in this example, but for returning very large, constant sized std::arrays, I do not want to rely on RVO.
Consider the following example:
#include <iostream>
struct foo {
foo(int) {}
foo(const foo&) { std::cout << "copy\n"; }
foo(foo&&) { std::cout << "move\n"; }
};
foo f() {
//return 42;
return { 42 };
}
int main() {
foo obj = f();
(void) obj;
}
When compiled with gcc 4.8.1 with -fno-elide-constructors to prevent RVO the output is
move
If in f the return statement without curly braces is used then, then the output is
move
move
With no RVO, what happens is the following. f must create a temporary object of type foo, let's call it ret, to be returned.
If return { 42 }; is used, then ret is direct initialized from the value 42. So no copy/move constructor was called so far.
If return 42; is used, then another temporary, let's call it tmp is direct initialized from 42 and tmp is moved to create ret. Hence, one move constructor was called so far. (Notice that tmp is an rvalue and foo has a move constructor. If there was no move constructor, then the copy constructor would be called.)
Now ret is an rvalue and is used to initialize obj. Hence the move constuctor is called to move from ret to obj. (Again, in some circumstances, the copy constructor could be called instead.) Hence either one (for return { 42 };) or two (for return 42;) moves happen.
As I said in my comment to the OP's question, this post is very relevant:
construction helper make_XYZ allowing RVO and type deduction even if XZY has noncopy constraint. Especially the excelent answer by
R. Martinho Fernandes.

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.

Why isn't the copy constructor elided here?

(I'm using gcc with -O2.)
This seems like a straightforward opportunity to elide the copy constructor, since there are no side-effects to accessing the value of a field in a bar's copy of a foo; but the copy constructor is called, since I get the output meep meep!.
#include <iostream>
struct foo {
foo(): a(5) { }
foo(const foo& f): a(f.a) { std::cout << "meep meep!\n"; }
int a;
};
struct bar {
foo F() const { return f; }
foo f;
};
int main()
{
bar b;
int a = b.F().a;
return 0;
}
It is neither of the two legal cases of copy ctor elision described in 12.8/15:
Return value optimisation (where an automatic variable is returned from a function, and the copying of that automatic to the return value is elided by constructing the automatic directly in the return value) - nope. f is not an automatic variable.
Temporary initializer (where a temporary is copied to an object, and instead of constructing the temporary and copying it, the temporary value is constructed directly into the destination) - nope f is not a temporary either. b.F() is a temporary, but it isn't copied anywhere, it just has a data member accessed, so by the time you get out of F() there's nothing to elide.
Since neither of the legal cases of copy ctor elision apples, and the copying of f to the return value of F() affects the observable behaviour of the program, the standard forbids it to be elided. If you got replaced the printing with some non-observable activity, and examined the assembly, you might see that this copy constructor has been optimised away. But that would be under the "as-if" rule, not under the copy constructor elision rule.
Copy elision happens only when a copy isn't really necessary. In particular, it's when there's one object (call it A) that exists for the duration of the execution of a function, and a second object (call it B) that will be copy constructed from the first object, and immediately after that, A will be destroyed (i.e. upon exit from the function).
In this very specific case, the standard gives permission for the compiler to coalesce A and B into two separate ways of referring to the same object. Instead of requiring that A be created, then B be copy constructed from A, and then A be destroyed, it allows A and B to be considered two ways of referring to the same object, so the (one) object is created as A, and after the function returns starts to be referred to as B, but even if the copy constructor has side effects, the copy that creates B from A can still be skipped over. Also, note that in this case A (as an object separate from B) is never destroyed either -- e.g., if your dtor also had side effects, they could (would) be omitted as well.
Your code doesn't fit that pattern -- the first object does not cease to exist immediately after being used to initialize the second object. After F() returns, there are two instances of the object. That being the case, the [Named] Return Value Optimization (aka. copy elision) simply does not apply.
Demo code when copy elision would apply:
#include <iostream>
struct foo {
foo(): a(5) { }
foo(const foo& f): a(f.a) { std::cout << "meep meep!\n"; }
int a;
};
int F() {
// RVO
std::cout << "F\n";
return foo();
}
int G() {
// NRVO
std::cout << "G\n";
foo x;
return x;
}
int main() {
foo a = F();
foo b = G();
return 0;
}
Both MS VC++ and g++ optimize away both copy ctors from this code with optimization turned on. g++ optimizes both away even if optimization is turned off. With optimization turned off, VC++ optimizes away the anonymous return, but uses the copy ctor for the named return.
The copy constructor is called because a) there is no guarantee you are copying the field value without modification, and b) because your copy constructor has a side effect (prints a message).
A better way to think about copy elision is in terms of the temporary object. That is how the standard describes it. A temporary is allowed to be "folded" into a permanent object if it is copied into the permanent object immediately before its destruction.
Here you construct a temporary object in the function return. It doesn't really participate in anything, so you want it to be skipped. But what if you had done
b.F().a = 5;
if the copy were elided, and you operated on the original object, you would have modified b through a non-reference.