I am developing a program for embedded system that will not use dynamic memory allocation. How can I prevent the GCC from producing deleting destructor (the destructor with D0 in its mangled name)? It will be never called.
I think that there is even no need to have deleting destructors, since the complete object destructor (D1 in mangled name) can be called instead along with operator delete(…) after it.
In my opinion, there should be some command-line option to disable these destructors.
The main problem is that the program calls operator delete(…) in the deleting destructor. Since I do not have any heap management, no such function is defined. As a workaround, I could implement operator delete(…) that just reports an error, but this would waste memory (unnecessarily large program size) and will not allow me to catch accidental call to operator delete() during the compilation.
The deleting destructor variant exists so that the syntax
where
ptrpoints to an polymorphic type can work even ifptrdoesn't point to the most-derived object. The user ofdelete ptr;doesn't know what the offset to the most-derived object or its size is, but it needs to know that in order to calloperator deletecorrectly. Therefore there needs to be an indirect/virtual call to a function that knows, which is the deleting destructor.Unfortunately the compiler has to generate the deleting destructor from such a
virtualdestructor at least for all classes which are used as most-derived objects, since there could be adeleteexpression of that kind in another translation unit that doesn't know about the definition of this most-derived destructor which it must however (indirectly) call.I don't think that you can separate the
deletebehavior of virtual destructors from the ability to do explicit virtual destructor calls and I also don't see any GCC switch to disable the generation of the deleting destructor as a non-standard/ABI conforming option.So I guess you'll have to avoid virtual destructors. You can get the virtual destruction behavior anyway by forwarding from a
virtualfunction:And then instead of
ptr->~Base();/std::destroy_at(ptr)you can useptr->destroy().However, this has the problem that you need to assure that
destructis properly overriden in every derived class to avoid undefined behavior. CRTP or C++23 explicit object parameters (explicitthis) may help with that.You also have the problem that someone might accidentally call the destructor directly, again causing undefined behavior. Making the destructor
privateis also generally not a solution because the destructor is potentially invoked in many situations, e.g. in a constructor of a class that contains the class in question as a non-static member.I originally suggested here to implement the
operator deleteas empty andinlinein every translation unit to help with removing the calls, however I didn't realize that marking the replaceable deallocation functions asinlinemakes the program IFNDR and so isn't valid. (See [replacement.functions]/3.)You can't delete the
operator delete, because it will be odr-used for the reasons I mentioned above and must therefore viable.LTO might further help getting rid of unused emitted deleting destructors during linking, at least via devirtualization. But I haven't tested.