Date: Mon, 28 Dec 2020 19:48:45 -0500
On Mon, Dec 28, 2020 at 7:13 PM Lénárd Szolnoki via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> On Sun, 27 Dec 2020 23:52:44 -0500 "Arthur O'Dwyer" <
> arthur.j.odwyer_at_[hidden]> wrote:
> > [...] 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. [...]
> I would prefer this to a separate rebind mechanism
I consider there to be two separate issues here:
(1) When we talk about "rebind", we're talking about a type-level operation
(FacilityType x NewElementType -> NewFacilityType). For example,
std::allocator<int>::rebind<double> is an alias for std::allocator<double>,
or std::shared_ptr<Foo>::rebind<Bar> is an alias for std::shared_ptr<Bar>.
(I'm omitting the actual traits-class stuff you'd have to type in real
life, for simplicity.)
(2) Converting constructors are the value-level counterpart (FacilityValue
x NewFacilityType -> NewFacilityValue). For example, if ai is a
std::allocator<int>, then std::allocator<double>(ai) is an
allocator<double> with "the same value" as ai.
So in order to implement `vector<bool>` or `map<K,V>`, you need both a way
to rebind the allocator type within the same "family," and appropriate
converting constructors so that you can actually create instances of the
rebound type once you've got it.
See my definition of "rebinding" in
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0773r0.html .
> [...] 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.
>
Well, it doesn't matter for deletion, if A's destructor is virtual. (And if
A's destructor is non-virtual, then you probably don't want to just delete
it like that.)
But it might conceivably matter for some user-defined deleter type that did
more than just `delete p`.
–Arthur
std-proposals_at_[hidden]> wrote:
> On Sun, 27 Dec 2020 23:52:44 -0500 "Arthur O'Dwyer" <
> arthur.j.odwyer_at_[hidden]> wrote:
> > [...] 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. [...]
> I would prefer this to a separate rebind mechanism
I consider there to be two separate issues here:
(1) When we talk about "rebind", we're talking about a type-level operation
(FacilityType x NewElementType -> NewFacilityType). For example,
std::allocator<int>::rebind<double> is an alias for std::allocator<double>,
or std::shared_ptr<Foo>::rebind<Bar> is an alias for std::shared_ptr<Bar>.
(I'm omitting the actual traits-class stuff you'd have to type in real
life, for simplicity.)
(2) Converting constructors are the value-level counterpart (FacilityValue
x NewFacilityType -> NewFacilityValue). For example, if ai is a
std::allocator<int>, then std::allocator<double>(ai) is an
allocator<double> with "the same value" as ai.
So in order to implement `vector<bool>` or `map<K,V>`, you need both a way
to rebind the allocator type within the same "family," and appropriate
converting constructors so that you can actually create instances of the
rebound type once you've got it.
See my definition of "rebinding" in
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0773r0.html .
> [...] 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.
>
Well, it doesn't matter for deletion, if A's destructor is virtual. (And if
A's destructor is non-virtual, then you probably don't want to just delete
it like that.)
But it might conceivably matter for some user-defined deleter type that did
more than just `delete p`.
–Arthur
Received on 2020-12-28 18:48:58