Boost logo

Boost :

Subject: Re: [boost] unique_ptr, was: Composing non copyable and movable classes
From: Chris Newbold (Chris.Newbold_at_[hidden])
Date: 2008-12-18 13:22:16


> From: boost-bounces_at_[hidden] [mailto:boost-
> bounces_at_[hidden]] 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.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk