Date: Mon, 15 Feb 2021 10:11:59 -0800
Now I know you're just kidding. Wouldn't a much easier way to handle your
last example would be to separate the three fields into three separate
classes, each to be handled properly there in their own class? Then this
class becomes rule-of-0? I hate to quote the stupid "laws", but: SRP.
On Mon, Feb 15, 2021 at 9:10 AM Maciej Polanski via Std-Discussion <
std-discussion_at_[hidden]> wrote:
> Generally, parametric destrucor syntax would need a "deinitialization
> list", symmetrically to constructor. I am not sure about details, but this
> would looks like:
>
> //---
> class cDerivedC : public cBaseC {
>
> std::string a; // on deinitialization list - handled manually, no
> auto-destructor
> std::string b; // on list with parameter - call delegated to its
> own parametric destructor
> std::string c; // not on list - normal (non parametric)
> automatic destructor
>
> public:
> ~cDerivedC (cDerivedSink* sink)
> baseC( (cBaseSink*)sink ),
> a,
> b(sink->b)
> { sink->TakeOverA(a);}
>
> };
> //------
>
> Then "destructive move", aka "DestructorConstructor", will be a special
> case of this general semantic.
>
> And default destructive move will have all those auto-matching correct
> fields capabilities that you propose, like moving field "a" to "target->a",
> initializing base class of target from base class of source itd.
>
>
> On 2021-02-13 01:08, Edward Catmur wrote:
>
> OK, I can see that destructor syntax is superior for that case.
>
> What about the issue of subobjects, though? Do those have their usual
> destructors called or is there opportunity to override that? In any case,
> in what order do destructors get called in - is it the usual order
> (backwards) or in reverse (forwards)?
>
> And what if you want to destructive move not into a region of storage but
> into a prvalue? Constructor syntax makes that easy to implement; destructor
> syntax would require considerable gymnastics from the compiler.
>
>
> On Fri, Feb 12, 2021 at 7:56 PM Maciej Polanski via Std-Discussion <
> std-discussion_at_[hidden]> wrote:
>
>> I can see a problem with constructor approach. There will be:
>>
>> 1. Zero-abstraction-cost way for data in - normal constructor, taking
>> e.g. naked pointer
>>
>> 2. Zero-abstraction-cost way of relocating data - e.g. "A(std::relocates,
>> A* ptr)"
>>
>> 3. But it lacks zero-abstraction-cost way of data out - at the end, there
>> is always a need to set pointers to zero and call destructor to do nothing
>>
>>
>> So any constructor approach will be somewhat incomplete, not covering
>> whole lifetime of data.
>>
>> The only way to elide spare destructor calls I can imagine, is to create
>> kind of "moving out destructor", that replaces default one. So that's why I
>> prefer destructor :)
>>
>>
>> PS. Seems I have some problem with discussion list, I hope this message
>> will be delivered correctly.
>>
>>
>> On 2021-02-12 18:41, Edward Catmur wrote:
>>
>> That's a very interesting use case, but it could easily be accommodated
>> in other proposals, e.g. in N4158 by allowing the two arguments to be of
>> different types.
>>
>> The reason I think that a constructor syntax is to be preferred is that
>> it's more difficult to set up class invariants than it is to leave a
>> class's members in a state where the destructor can be elided without a
>> leak. For instance, what happens if someone adds a std::string member to
>> your type? - under a constructor-style proposal, a member that is not
>> explicitly initialized in the mem-initializer-list can be automatically
>> initialized by destructive move from the corresponding member on the other
>> instance (of the same type).
>>
>> On Fri, Feb 12, 2021 at 12:43 PM Maciej Polanski via Std-Discussion <
>> std-discussion_at_[hidden]> wrote:
>>
>>>
>>> On 2021-02-11 20:02, Edward Catmur via Std-Discussion wrote:
>>> > This would operate very similarly to the current proposal, but with
>>> > the possibly unintuitive difference that the new object is being
>>> > passed as the parameter, so that e.g. ~c(x.c) initializes x.c with the
>>> > value of c. Furthermore, it would require re-inventing syntax to allow
>>> > for move construction of subobjects.
>>>
>>> While approaches "Constructor that destructs its argument" and
>>> "Destructor that constructs its argument" seems to be just symmetrical,
>>> my DestrcutorConstructor would have one more feature: it allows
>>> "destructing move" depositing object's data in object of other class, or
>>> even a function.
>>>
>>> So without judging if this is worth efforts or not, I'd like to
>>> highlight this part of my proposal:
>>>
>>> //------
>>> // class to receive data from object being deleted
>>> class cDataSink {
>>> public:
>>> TakeOverData(cSomeData*);
>>> }
>>>
>>> // class that can be deleted with real zero-additional-cost transfer of
>>> data:
>>> class C {
>>> cSomeData *pDdata;
>>>
>>> public:
>>> ~C(cDataSink* sink) { sink->TakeOverData(data); } // <-
>>> DepositingDestructor here
>>> ~C() { delete pData; } // Normal
>>> destructor
>>> };
>>> //------
>>>
>>> Regards,
>>> Maciej
>>>
>>> --
>>> Std-Discussion mailing list
>>> Std-Discussion_at_[hidden]
>>> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>>>
>> --
>> Std-Discussion mailing list
>> Std-Discussion_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>>
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>
last example would be to separate the three fields into three separate
classes, each to be handled properly there in their own class? Then this
class becomes rule-of-0? I hate to quote the stupid "laws", but: SRP.
On Mon, Feb 15, 2021 at 9:10 AM Maciej Polanski via Std-Discussion <
std-discussion_at_[hidden]> wrote:
> Generally, parametric destrucor syntax would need a "deinitialization
> list", symmetrically to constructor. I am not sure about details, but this
> would looks like:
>
> //---
> class cDerivedC : public cBaseC {
>
> std::string a; // on deinitialization list - handled manually, no
> auto-destructor
> std::string b; // on list with parameter - call delegated to its
> own parametric destructor
> std::string c; // not on list - normal (non parametric)
> automatic destructor
>
> public:
> ~cDerivedC (cDerivedSink* sink)
> baseC( (cBaseSink*)sink ),
> a,
> b(sink->b)
> { sink->TakeOverA(a);}
>
> };
> //------
>
> Then "destructive move", aka "DestructorConstructor", will be a special
> case of this general semantic.
>
> And default destructive move will have all those auto-matching correct
> fields capabilities that you propose, like moving field "a" to "target->a",
> initializing base class of target from base class of source itd.
>
>
> On 2021-02-13 01:08, Edward Catmur wrote:
>
> OK, I can see that destructor syntax is superior for that case.
>
> What about the issue of subobjects, though? Do those have their usual
> destructors called or is there opportunity to override that? In any case,
> in what order do destructors get called in - is it the usual order
> (backwards) or in reverse (forwards)?
>
> And what if you want to destructive move not into a region of storage but
> into a prvalue? Constructor syntax makes that easy to implement; destructor
> syntax would require considerable gymnastics from the compiler.
>
>
> On Fri, Feb 12, 2021 at 7:56 PM Maciej Polanski via Std-Discussion <
> std-discussion_at_[hidden]> wrote:
>
>> I can see a problem with constructor approach. There will be:
>>
>> 1. Zero-abstraction-cost way for data in - normal constructor, taking
>> e.g. naked pointer
>>
>> 2. Zero-abstraction-cost way of relocating data - e.g. "A(std::relocates,
>> A* ptr)"
>>
>> 3. But it lacks zero-abstraction-cost way of data out - at the end, there
>> is always a need to set pointers to zero and call destructor to do nothing
>>
>>
>> So any constructor approach will be somewhat incomplete, not covering
>> whole lifetime of data.
>>
>> The only way to elide spare destructor calls I can imagine, is to create
>> kind of "moving out destructor", that replaces default one. So that's why I
>> prefer destructor :)
>>
>>
>> PS. Seems I have some problem with discussion list, I hope this message
>> will be delivered correctly.
>>
>>
>> On 2021-02-12 18:41, Edward Catmur wrote:
>>
>> That's a very interesting use case, but it could easily be accommodated
>> in other proposals, e.g. in N4158 by allowing the two arguments to be of
>> different types.
>>
>> The reason I think that a constructor syntax is to be preferred is that
>> it's more difficult to set up class invariants than it is to leave a
>> class's members in a state where the destructor can be elided without a
>> leak. For instance, what happens if someone adds a std::string member to
>> your type? - under a constructor-style proposal, a member that is not
>> explicitly initialized in the mem-initializer-list can be automatically
>> initialized by destructive move from the corresponding member on the other
>> instance (of the same type).
>>
>> On Fri, Feb 12, 2021 at 12:43 PM Maciej Polanski via Std-Discussion <
>> std-discussion_at_[hidden]> wrote:
>>
>>>
>>> On 2021-02-11 20:02, Edward Catmur via Std-Discussion wrote:
>>> > This would operate very similarly to the current proposal, but with
>>> > the possibly unintuitive difference that the new object is being
>>> > passed as the parameter, so that e.g. ~c(x.c) initializes x.c with the
>>> > value of c. Furthermore, it would require re-inventing syntax to allow
>>> > for move construction of subobjects.
>>>
>>> While approaches "Constructor that destructs its argument" and
>>> "Destructor that constructs its argument" seems to be just symmetrical,
>>> my DestrcutorConstructor would have one more feature: it allows
>>> "destructing move" depositing object's data in object of other class, or
>>> even a function.
>>>
>>> So without judging if this is worth efforts or not, I'd like to
>>> highlight this part of my proposal:
>>>
>>> //------
>>> // class to receive data from object being deleted
>>> class cDataSink {
>>> public:
>>> TakeOverData(cSomeData*);
>>> }
>>>
>>> // class that can be deleted with real zero-additional-cost transfer of
>>> data:
>>> class C {
>>> cSomeData *pDdata;
>>>
>>> public:
>>> ~C(cDataSink* sink) { sink->TakeOverData(data); } // <-
>>> DepositingDestructor here
>>> ~C() { delete pData; } // Normal
>>> destructor
>>> };
>>> //------
>>>
>>> Regards,
>>> Maciej
>>>
>>> --
>>> Std-Discussion mailing list
>>> Std-Discussion_at_[hidden]
>>> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>>>
>> --
>> Std-Discussion mailing list
>> Std-Discussion_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>>
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>
Received on 2021-02-15 12:12:13