<div dir="ltr"><div>As everybody said you can not call a derived implementation from a base d&#39;tor because the data for that derived class is gone and your &quot;close()&quot; would not know what to close.</div><div>This is just a point of religion and design philosophy that you will never get changed.</div><div><br></div>An option you might consider is to have the derived c&#39;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&#39;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&#39;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().<div><br></div><div>A(nother) flaw with your &#39;derived_invokes&#39; 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.</div><div><br></div><div>Chris++;</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, May 29, 2024 at 12:36 PM Nikolay Mihaylov via Std-Proposals &lt;<a href="mailto:std-proposals@lists.isocpp.org" target="_blank">std-proposals@lists.isocpp.org</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">my 5 cents <div><br></div><div>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 &quot;correct&quot; state - e.g. memory freed, but pointer pointing somewhere etc.</div><div><br></div><div>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.</div><div><br></div><div>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.</div><div><br></div><div>Nikolay</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, May 29, 2024 at 10:28 PM Lorand Szollosi via Std-Proposals &lt;<a href="mailto:std-proposals@lists.isocpp.org" target="_blank">std-proposals@lists.isocpp.org</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div>Hi,</div><div><br></div><div>You have an XY-problem.</div><div><br></div></div><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, May 29, 2024 at 12:38 PM Frederick Virchanza Gotham via Std-Proposals &lt;<a href="mailto:std-proposals@lists.isocpp.org" target="_blank">std-proposals@lists.isocpp.org</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">    class RS232 : public IRS232 {};<br>        virtual ~RS232(void) noexcept { this-&gt;Close(); }<br>    RS232_Microcontroller::~RS232_Microcontroller   must call    &quot;this-&gt;Close()&quot;<br>
    RS232_Win32::~RS232_Win32   must call    &quot;this-&gt;Close()&quot;<br>
    RS232_Boost::~RS232_Boost   must call    &quot;this-&gt;Close()&quot;<br></blockquote><div>The things you&#39;d like to run <i>before</i> destructor is not in the <i>base</i>, but in the <i>descendant</i>.</div><div><br></div><div>Thus, you <i>can</i> have a base for the interface:</div><div><font face="monospace">class IRS232 { /* common stuff, any virtuals if you don&#39;t like concepts */ };</font></div><div><br></div><div>You have an implementation hierarchy:</div><div><font face="monospace">class RS232 : public IRS232 { /* dtor doesn&#39;t call close */ };</font></div><div><br></div><div>You have the system-specific implementations of any number of layers:</div><div><font face="monospace">class RS232_Arch_Impl : public RS232 { /* dtor still doesn&#39;t call close */ };</font></div><div><br></div><div>And you have the top layer:</div><div><font face="monospace">template&lt;typename T&gt;</font></div><div><font face="monospace">struct RS232_Top : T {</font></div><div><font face="monospace">    ~RS232_Top { Close(); }  // you&#39;re free to have preClose(), Close(), afterClose(), etc.</font></div><div><font face="monospace">};</font></div><div><font face="monospace"><br></font></div><div><font face="monospace">using RS232_Arch = RS232_Top&lt;RS232_Arch_Impl&gt;;</font></div><div> <br></div><div>This ensures that <font face="monospace">Close()</font> is called <i>before</i> dtor of your implementation. And it&#39;s done.</div><div><br></div><div>As for the proposed feature,</div><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
        virtual ~IRS232(void) noexcept derived_invokes(Close) {}<br></blockquote><div>[...] </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">The purpose of this proposed new feature is that instead of creating<br>
bugs that are discovered a runtime, you get a compiler error.</blockquote><div><div>It&#39;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. </div></div><div><br></div><div>Also, since it&#39;s 2024..., I&#39;d consider twice before writing virtual for an interface. We have CRTP, concepts, even deducing <font face="monospace">this</font>. I&#39;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.</div><div><br></div><div>Thanks,</div><div>-lorro</div><div><br></div><div><br></div></div></div>
-- <br>
Std-Proposals mailing list<br>
<a href="mailto:Std-Proposals@lists.isocpp.org" target="_blank">Std-Proposals@lists.isocpp.org</a><br>
<a href="https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals" rel="noreferrer" target="_blank">https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals</a><br>
</blockquote></div>
-- <br>
Std-Proposals mailing list<br>
<a href="mailto:Std-Proposals@lists.isocpp.org" target="_blank">Std-Proposals@lists.isocpp.org</a><br>
<a href="https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals" rel="noreferrer" target="_blank">https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals</a><br>
</blockquote></div>

