C++ Logo

std-proposals

Advanced search

Re: pointer_cast for unique_ptr

From: Lénárd Szolnoki <cpp_at_[hidden]>
Date: Tue, 29 Dec 2020 00:13:15 +0000
On Sun, 27 Dec 2020 23:52:44 -0500
"Arthur O'Dwyer" <arthur.j.odwyer_at_[hidden]> wrote:

> On Sun, Dec 27, 2020 at 10:16 PM connor horman via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
> > To std::default_deleter<T> [...] modify the constructor of
> > default_deleter to participate in overload resolution if any of the
> > following is true:
> > - U is a (possibly virtual) base class of T (does this need to allow
> > inaccessible base classes, or is that not permitted by an implicit
> > conversion),
> > - T is an accessible (possibly virtual) base class of U, in a
> > context unrelated to both T and U,
> > - U is (possibly-differently cv-qualified) T, or
> > - Both T and U are polymorphic types and U has a virtual destructor.
> >
>
> This part sounds like Lénárd Szolnoki's proposal for further
> constraining constructors of default_delete. I've got an
> implementation of it here:
> https://github.com/Quuxplusone/llvm-project/commit/ec526c22aa43954d35356f63b55867c16aa08e88
> and on Godbolt: https://p1144.godbolt.org/z/hEYz6c
> (Lénárd, have you written a paper for this proposal yet? Shouldn't
> you, or someone, do that?)
>

Yes, coming soon. Notable that there is already a "rebind" mechanism of
default_delete, its converting constructor. Unfortunately it's not
usable for static/dynamic/const pointer cast, as it's constrained on
regular pointer convertibility. I think that's wrong and that constrain
could be removed (along with constraining it an other way for keeping
polymorphic delete safe), but I expect some push back on that. I need a
precise semantic constraint on a pair of deleters for that to be
provably correct, but I don't have that yet.

I would prefer this to a separate rebind mechanism if this works out.

>
> > template<typename U,typename T,typename D>
> > std::unique_ptr<U,REBIND_DELETER<D,U>>
> > dynamic_pointer_cast(std::unique_ptr<T,D>&& ptr)
> > - Performs a type qualification conversion of a unique_ptr, as
> > though by const_cast
> > - Only participates in overload resolution if REBIND_DELETER<D,U>
> > is well formed and constructible from D,
> > typename std::pointer_traits<typename D::pointer>::template
> > rebind<U> is implicitly convertible to typename
> > REBIND_DELETER<D,U>::pointer, the conversion from T* to U* may be
> > performed by a valid dynamic_cast
>
> I haven't tried to decipher your REBIND_DELETER stuff, but I suspect
> that you're going to have trouble with the fact that dynamic_cast is
> not reversible: it's quite possible to have an A *a1, dynamic_cast it
> to a B*, dynamic_cast the B* back to an A*, and end up with a
> completely different object! So if your strategy is to return a
> unique_ptr<B, SomeDeleter> with a deleter that dynamic_casts B* back
> to A* and deletes that with the original deleter... well, that's not
> going to work the way you wanted. https://godbolt.org/z/Y376Kr

I don't think that the non-reversibility of dynamic_cast is a problem
for default delete. Does it matter which A subobject of a D
complete object the pointer points to when you delete it? This seems to
be a red herring for me, but correct me if I'm wrong.

>
> In real code, I'd want to see a function named clearly after its
> purpose, e.g. `ptr_downcast` if you want to use it for downcasts
> within a hierarchy: https://godbolt.org/z/abG33b
> If I saw someone trying to do this in the presence of a custom
> deleter, and/or via a generically named function like
> `static_pointer_cast`, I'd bet that they didn't know what they were
> doing.
>
> –Arthur

Cheers,
Lénárd

Received on 2020-12-28 18:13:21