From 6995752608695356048
X-Google-Thread: f78e5,52dd3e1082ac085e
X-Google-Attributes: gidf78e5,public
X-Google-Language: ENGLISH,ASCII-7-bit
Path: g2news1.google.com!news4.google.com!news.glorb.com!news.cs.univ-paris8.fr!newsfeed.vmunix.org!peer-uk.news.demon.net!kibo.news.demon.net!news.demon.co.uk!demon!stump.algebra.com!devnull
From: hinnant@metrowerks.com (Howard Hinnant)
Newsgroups: comp.std.c++
Subject: Re: unique_ptr
Date: Sat,  3 Sep 2005 05:23:04 GMT
Organization: Metrowerks
Lines: 129
Sender: mail2news@demon.net
Approved: fjh@cs.mu.oz.au (Fergus Henderson , moderator of comp.std.c++)
Message-ID: <hinnant-8804B5.11081102092005@syrcnyrdrs-03-ge0.nyroc.rr.com>
References: <1125603471.570361.32720@o13g2000cwo.googlegroups.com>
NNTP-Posting-Host: news.news.demon.net
X-Trace: news.demon.co.uk 1125726048 26694 158.152.254.254 (3 Sep 2005 05:40:48 GMT)
X-Complaints-To: abuse@demon.net
NNTP-Posting-Date: Sat, 3 Sep 2005 05:40:48 +0000 (UTC)
X-Robomod: STUMP, ichudov@algebra.com (Igor Chudov)
X-User-Agent: MT-NewsWatcher/3.4 (PPC Mac OS X)
X-Virus-Scanned: amavisd-new at cs.mu.OZ.AU
X-Received: (from fjh@localhost)
	by mulga.cs.mu.OZ.AU (8.12.10+Sun/8.12.9/Submit) id j835N4qR007556;
	Sat, 3 Sep 2005 15:23:04 +1000 (EST)
X-Path: comp-std-cpp-robomod!not-for-mail
X-NNTP-Posting-Date: Fri, 02 Sep 2005 11:08:11 EDT
X-Delivered-To: std-c++@ucar.edu
X-Authentication-Warning: mulga.cs.mu.OZ.AU: fjh set sender to devnull@stump.algebra.com using -f
X-Newsgroups: comp.std.c++
Xref: g2news1.google.com comp.std.c++:2002

In article <1125603471.570361.32720@o13g2000cwo.googlegroups.com>,
 "l.j.persson@gmail.com" <l.j.persson@gmail.com> wrote:

> Hello,
> I was just reading the excellent proposal on unique_ptr
> (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1856.html).
> But I have a question on the constructor: why doesn't it take a T*&&
> parameter?
> 
> explicit unique_ptr(T*&& p);
> 
> If I understand rvalues correctly that would mean:
> 
> unique_ptr<int> ui(new int); // Ok
> int* pi = new int;
> unique_ptr<int> ui(pi); // Not Ok
> 
> In current implementation we have
> 
> int* pi = new int;
> unique_ptr<int> ui1(pi); // Ok
> unique_ptr<int> ui2(pi); // Ok, but no good
> 
> same applies to operator=() and reset().

That's a very interesting suggestion!

I must admit that I'm waffling on it at the moment.  At first I thought 
it sounded great, and I prototyped it right up.  But then I used that 
prototype to start looking at some of my use cases, and my enthusiasm is 
waning.

There are times when you really do want to assign an lvalue pointer to a 
unique_ptr.  In fact N1856 outlines one such case:

// A::foo establishes ownership of p, but
// must acquire other resources to do so.  A local
// unique_ptr is used as an aid to hold on to p while
// those other resources are acquired.
template<class T, class D>
void
A<T, D>::foo(T* p)
{
    // Establish preliminary ownership without requiring
    // a copy of the deleter D
    std::unique_ptr<T, D&> hold(p, deleter_);  // no throw
    // acquire resources                       // if throws,
    // ...                                     //    deleter_(p) executed
    // transfer ownership to A
    p_ = hold.release();                       // no throw
}

With your suggestion that would change to:

template<class T, class D>
void
A<T, D>::foo(T* p)
{
    // Establish preliminary ownership without requiring
    // a copy of the deleter D
    std::unique_ptr<T, D&> hold(std::move(p), deleter_);  // no throw
    // acquire resources                       // if throws,
    // ...                                     //    deleter_(p) executed
    // transfer ownership to A
    p_ = hold.release();                       // no throw
}

Now that doesn't look too bad.  But then I went back to the source, the 
actual code that the A::foo example is derived from, and it begins to 
look worse:

template<class T>
template<class Y, class D>
shared_ptr<T>::shared_ptr(Y* p, D&& d)
    : ptr_(p)
{
    Metrowerks::move_ptr<Y, D&> hold(p, d);
    s_ = new detail::shared_ptr_deleter<Y, D>(p, d);
    hold.release();
    ...
}

Now you can see that "p" is assigned several places in this code.  Which 
of those places should be changed to move(p)?

(Metrowerks::move_ptr is the proposed std::unique_ptr).

The fact is that after I "own" p with the unique_ptr, I subsequently 
also pass ownership of p to the shared_ptr - without first relinquishing 
ownership from the unique_ptr!  And that is as it should be.  So should 
the code look like this:

template<class T>
template<class Y, class D>
shared_ptr<T>::shared_ptr(Y* p, D&& d)
    : ptr_(p)
{
    Metrowerks::move_ptr<Y, D&> hold(move(p), d);
    s_ = new detail::shared_ptr_deleter<Y, D>(move(p), d);
    hold.release();
    ...
}

I guess what I'm getting at, and not expressing too eloquently at the 
moment, is that I believe accepting only rvalue pointers in the 
unique_ptr ctor might lead to code that just liberally sprinkled move(p) 
expressions around, and the resulting code is really no safer than it is 
without the move(p) expressions.

Ok, gathering my thoughts a little more (maybe):

Assertion:

An rvalue pointer is not intrinsically safer to pass to a smart pointer 
than is an lvalue pointer.

But this is a most interesting suggestion!  And thank you for making it.  
I would be most interested to continue this discussion and collect a 
wide range of opinions.  This is a feature I had not previously thought 
about and we would be remiss not to fully explore it.

-Howard

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]



