Edit: my bad, you DO need to write move(p)
inside the initialiser. std::move
treats whatever it's given as an rvalue reference, and in your case, even though your argument is an rvalue reference to something, passing it to something else (like p_
's constructor) will pass an lvalue reference, never an rvalue reference by default.
Per Karu's comment, also added necessary includes to made my code compilable.
For example:
#include <memory>
#include <cassert>
#include <vector>
using namespace std;
class A {};
class B {
public:
void takeOwnershipOf(unique_ptr<A>&& rhs) {
// We need to explicitly cast rhs to an rvalue when passing it to push_back
// (otherwise it would be passed as an lvalue by default, no matter what
// qualifier it has in the argument list). When we do that, the move
// constructor of unique_ptr will take ownership of the pointed-to value
// inside rhs, thus making rhs point to nothing.
owned_objects.push_back(std::move(rhs));
}
private:
vector<unique_ptr<A>> owned_objects;
};
int main() {
unique_ptr<B> b(new B());
// we don't need to use std::move here, because the argument is an rvalue,
// so it will automatically be transformed into an rvalue reference.
b->takeOwnershipOf( unique_ptr<A>(new A()) );
unique_ptr<A> a (new A());
// a points to something
assert(a);
// however, here a is an lvalue (it can be assigned to). Thus we must use
// std::move to convert a into an rvalue reference.
b->takeOwnershipOf( std::move(a) );
// whatever a pointed to has now been moved; a doesn't own it anymore, so
// a points to 0.
assert(!a);
return 0;
}
Also, in your original example, you should rewrite class A like this:
class A {
// takes ownership
A(unique_ptr
&& p): p_(std::move(p)) {}
unique_ptr<P> p_;
};
`. Not only will unique_ptr call delete[] when it's deallocated, but it disables the * and -> operators instead it provides a [] operator.
– deft_code Jun 11 '10 at 18:02