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