C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Call virtual method from base's destructor

From: Chris Ryan <chrisr98008_at_[hidden]>
Date: Wed, 29 May 2024 14:02:46 -0700
As everybody said you can not call a derived implementation from a base
d'tor because the data for that derived class is gone and your "close()"
would not know what to close.
This is just a point of religion and design philosophy that you will never
get changed.

An option you might consider is to have the derived c'tor (or an open()
function) create a lambda to do the close() and register that lambda (via
pfn) with the base class. The base d'tor could call the base close() who
would invoke the lambda to do the real close. This way the derived
implementation sets how to do the close and the base d'tor/close() do the
work. By wrapping the call in the base close anybody wanting to close the
resource early can call the base close().

A(nother) flaw with your 'derived_invokes' is what if it is not the
immediately derived class implementation but a third or fourth level
derivative that would do the action. It looks like you are thinking it
must be in the immediately derived class plus the base (or middle layer)
has no idea who will derive from it or who will implement it.

Chris++;

On Wed, May 29, 2024 at 12:36 PM Nikolay Mihaylov via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> my 5 cents
>
> when base class d-tor is called all other children d-tors are already
> called and may be children object / classes may not be in "correct" state -
> e.g. memory freed, but pointer pointing somewhere etc.
>
> I did not follow the example, but if we have COMPort as a base and
> RS232_Boost as a child class, closing the port should be done in
> RS232_Boost d-tor.
>
> And yes, I agree it would be nice if you can close the port in COMPort
> d-tor, but in reality the RS232_Boost might not even exist at that moment.
>
> Nikolay
>
> On Wed, May 29, 2024 at 10:28 PM Lorand Szollosi via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> Hi,
>>
>> You have an XY-problem.
>>
>> On Wed, May 29, 2024 at 12:38 PM Frederick Virchanza Gotham via
>> Std-Proposals <std-proposals_at_[hidden]> wrote:
>>
>>> class RS232 : public IRS232 {};
>>> virtual ~RS232(void) noexcept { this->Close(); }
>>> RS232_Microcontroller::~RS232_Microcontroller must call
>>> "this->Close()"
>>> RS232_Win32::~RS232_Win32 must call "this->Close()"
>>> RS232_Boost::~RS232_Boost must call "this->Close()"
>>>
>> The things you'd like to run *before* destructor is not in the *base*,
>> but in the *descendant*.
>>
>> Thus, you *can* have a base for the interface:
>> class IRS232 { /* common stuff, any virtuals if you don't like concepts
>> */ };
>>
>> You have an implementation hierarchy:
>> class RS232 : public IRS232 { /* dtor doesn't call close */ };
>>
>> You have the system-specific implementations of any number of layers:
>> class RS232_Arch_Impl : public RS232 { /* dtor still doesn't call close
>> */ };
>>
>> And you have the top layer:
>> template<typename T>
>> struct RS232_Top : T {
>> ~RS232_Top { Close(); } // you're free to have preClose(), Close(),
>> afterClose(), etc.
>> };
>>
>> using RS232_Arch = RS232_Top<RS232_Arch_Impl>;
>>
>> This ensures that Close() is called *before* dtor of your
>> implementation. And it's done.
>>
>> As for the proposed feature,
>>
>>
>>> virtual ~IRS232(void) noexcept derived_invokes(Close) {}
>>>
>> [...]
>>
>>> The purpose of this proposed new feature is that instead of creating
>>> bugs that are discovered a runtime, you get a compiler error.
>>
>> It's equivalent to the halting problem (i.e., Turing-complete) to check
>> for an arbitrary code whether it calls a function. (It could call it
>> conditionally e.g. in a loop or it could be called from a function / lambda
>> it conditionally calls, or via a function ptr, or via a pointer that was
>> written to a file and then read back, etc.) So it cannot be verified in
>> compile-time.
>>
>> Also, since it's 2024..., I'd consider twice before writing virtual for
>> an interface. We have CRTP, concepts, even deducing this. I'd argue
>> that, on most architectures virtual is nowadays mainly for forward
>> compatibility, i.e., to be able to support descendants whose implementation
>> is not yet available at the time you compile the calling code (a notable
>> exception to this is cacheless MIPS architectures). That simplifies the
>> code even more I think.
>>
>> Thanks,
>> -lorro
>>
>>
>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>

Received on 2024-05-29 21:03:01