禁用删除析构函数的生成

jiw*_*ene 2 c++ embedded gcc destructor freestanding

我正在开发一个不使用动态内存分配的嵌入式系统程序。如何防止 GCC 生成删除析构函数D0(名称中含有损坏的析构函数)?它永远不会被调用。

\n

我认为甚至不需要删除析构函数,因为可以在其之后调用完整的对象析构函数(以损坏的名称) 。D1operator delete(\xe2\x80\xa6)

\n

在我看来,应该有一些命令行选项来禁用这些析构函数。

\n
\n

主要问题是程序调用operator delete(\xe2\x80\xa6)了删除析构函数。由于我没有任何堆管理,因此没有定义这样的函数。作为一种解决方法,我可以实现operator delete(\xe2\x80\xa6)仅报告错误,但这会浪费内存(不必要的大程序大小)并且不允许我operator delete()在编译期间捕获意外调用。

\n

use*_*522 5

存在删除析构函数变体,因此语法

delete ptr;
Run Code Online (Sandbox Code Playgroud)

ptr即使ptr不指向最派生的对象,指向多态类型的where也可以工作。的用户delete ptr;不知道最派生对象的偏移量或其大小是多少,但需要知道这一点才能operator delete正确调用。因此,需要对知道的函数进行间接/虚拟调用,即删除析构函数。

不幸的是,编译器必须virtual至少为所有用作最派生对象的类从这样的析构函数生成删除析构函数,因为delete在另一个不知道此定义的翻译单元中可能存在此类表达式然而,它必须(间接)调用最派生的析构函数。


我不认为你可以将delete虚拟析构函数的行为与执行显式虚拟析构函数调用的能力分开,而且我也没有看到任何 GCC 开关来禁用删除析构函数的生成作为非标准/ABI 符合选项。

所以我想你必须避免虚拟析构函数。无论如何,您都可以通过从函数转发来获得虚拟销毁行为virtual

struct Base {
    virtual destroy() noexcept { this->~Base(); }
    // destructor not virtual
};

struct Derived {
    virtual destroy() noexcept override { this->~Derived(); }
};
Run Code Online (Sandbox Code Playgroud)

然后您可以使用代替ptr->~Base();/ 。std::destroy_at(ptr)ptr->destroy()

但是,这存在一个问题,您需要确保destruct在每个派生类中正确重写以避免未定义的行为。CRTP 或 C++23 显式对象参数 (explicit this) 可能会对此有所帮助。

您还存在一个问题,即有人可能会意外地直接调用析构函数,再次导致未定义的行为。制作析构函数private通常也不是解决方案,因为析构函数可能在许多情况下被调用,例如,在包含所讨论的类作为非静态成员的类的构造函数中。


我最初建议在每个翻译单元中实现operator delete为空,inline以帮助删除调用,但是我没有意识到将可替换的释放函数标记为inline使程序 IFNDR 等无效。(参见[replacement.functions]/3。)

您无法删除operator delete,因为由于我上面提到的原因,它将被 odr 使用,因此必须可行。


LTO 可能会进一步帮助摆脱链接过程中未使用的发出的删除析构函数,至少是通过去虚拟化。但我没有测试过。