Boost logo

Boost :

Subject: Re: [boost] unique_ptr, was: Composing non copyable and movable classes
From: Howard Hinnant (hinnant_at_[hidden])
Date: 2008-12-18 13:48:40


On Dec 18, 2008, at 10:22 AM, Chris Newbold wrote:

>> 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?

Your conclusion is correct. And this is not a problem. moves from
lvalues (p1) should be explicit, even in C++0X. Here the emulation is
perfect.

Note that if p1 is an rvalue, the move is implicit, both emulated and
in C++0X:

unique_ptr<int> g();

void f() {
    unique_ptr<int> p2(g()); // implicit move, good
}

One place the emulation breaks down is inside of g():

unique_ptr<int>
g()
{
     unique_ptr<int> p;
     // ...
     return move(p); // ! explicit move necessary for emulation,
unwanted in C++0X
}

In C++0X one should say:

     return p;

instead. Putting the "move" on the return statement will inhibit rvo,
probably making your code slower. But in C++03 emulation, the move is
required, else you get a compile time error. If you can build the
return value in the return statement, then both C++03 emulation and C+
+0X are identical:

unique_ptr<int>
g()
{
     return unique_ptr<int>(); // implicit move, good
}

Another currently weak place in the emulation is that "move" is
injected as a friend of the move-only class. In C++0X, move is a
std::lib function, not to be implemented by user code. And user code
should always call std::move(x), not move(x).

-Howard

>
>
> -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.
>
>
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost


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