
From: boost-bounces@lists.boost.org [mailto:boost- bounces@lists.boost.org] On Behalf Of Howard Hinnant Sent: Wednesday, December 10, 2008 4:28 PM
Here's a sketch of what Sebastian is referring to. It isn't a complete unique_ptr. It is just a move-only-foundation to build off of.
... We've got a number of use-cases where unique_ptr would be extremely helpful. So, I figured I'd take a stab at a reasonable emulation and see how far I could get. I started playing around with Howard's skeleton to convince myself that I understood enough about rvalue references and move semantics to be able to finish the implementation. What I found, though, is that my understanding is lacking, particularly with regard to attempting to emulate the correct behavior in a C++03 world. Given Howard's skeleton, I tried the following test case: void f() { unique_ptr<int> p1(new int); unique_ptr<int> p2(p1); } This of course does not compile because there is no publically accessible constructor for unique_ptr that can do the job. The conversions and constructors using 'rv' aren't accessible either. In the end, I concluded that emulation on C++03 could provide move semantics, but that move operations need to be explicit, not implicit. That is, the test case should be: void f() { unique_ptr<int> p1(new int); unique_ptr<int> p2(move(p1)) } Is my conclusion correct? -Chris
template <class T> class unique_ptr { T* ptr_;
unique_ptr(unique_ptr&); unique_ptr& operator=(unique_ptr&);
class rv { unique_ptr& r_; public: explicit rv(unique_ptr& r) : r_(r) {} unique_ptr* operator->() {return &r_;} };
public:
operator rv() {return rv(*this);} unique_ptr(rv r) : ptr_(r->release()) {} unique_ptr& operator=(rv r) {reset(r->release()); return *this;} friend unique_ptr move(unique_ptr& u) {return unique_ptr(rv(u));} friend unique_ptr move(rv r) {return unique_ptr(r);}
explicit unique_ptr(T* p = 0) : ptr_(p) {} template <class U> unique_ptr(unique_ptr<U> u) : ptr_(u.release()) {} ~unique_ptr() {reset();}
template <class U> unique_ptr& operator=(unique_ptr<U> u) {reset(u.release()); return *this;}
T* release() { T* tmp = ptr_; ptr_ = 0; return tmp; }
void reset(T* ptr = 0) { if (ptr_) delete ptr_; ptr_ = ptr; } };
It isn't a perfect emulation. But I think it is pretty close. And where it fails, it is not a dangerous failure like moving from a const.