提问人:jiwopene 提问时间:9/3/2023 更新时间:9/15/2023 访问量:95
禁用删除析构函数的生成
Disable generation of deleting destructor
问:
我正在为嵌入式系统开发一个不使用动态内存分配的程序。如何防止 GCC 生成删除析构函数(名称中带有损坏的析构函数)?它永远不会被调用。D0
我认为甚至没有必要删除析构函数,因为完整的对象析构函数(以残缺的名称)可以在它之后调用。D1
operator delete(…)
在我看来,应该有一些命令行选项来禁用这些析构函数。
主要问题是程序调用删除析构函数。由于我没有任何堆管理,因此没有定义这样的函数。作为一种解决方法,我可以只报告错误,但这会浪费内存(不必要的大程序大小),并且不允许我在编译过程中捕获意外调用。operator delete(…)
operator delete(…)
operator delete()
答:
存在删除析构函数变体,以便语法
delete ptr;
即使不指向派生最多的对象,指向多态类型的 where 也可以工作。的用户不知道最派生对象的偏移量或其大小是多少,但它需要知道这一点才能正确调用。因此,需要对知道的函数进行间接/虚拟调用,该函数是删除析构函数。ptr
ptr
delete ptr;
operator delete
不幸的是,编译器必须从这样的析构函数生成删除析构函数,至少对于用作大多数派生对象的所有类,因为在另一个翻译单元中可能存在这种表达式,该表达式不知道这个最派生的析构函数的定义,但它必须(间接)调用。virtual
delete
我不认为您可以将虚拟析构函数的行为与执行显式虚拟析构函数调用的能力分开,并且我也没有看到任何 GCC 开关来禁用删除析构函数的生成作为非标准/ABI 符合选项。delete
所以我想你必须避免使用虚拟析构函数。无论如何,您都可以通过从函数转发来获取虚拟销毁行为:virtual
struct Base {
virtual destroy() noexcept { this->~Base(); }
// destructor not virtual
};
struct Derived {
virtual destroy() noexcept override { this->~Derived(); }
};
然后你可以用 .ptr->~Base();
std::destroy_at(ptr)
ptr->destroy()
但是,这有一个问题,您需要确保在每个派生类中正确覆盖该类,以避免未定义的行为。CRTP 或 C++23 显式对象参数(显式)可能会有所帮助。destruct
this
您还存在一个问题,即有人可能会不小心直接调用析构函数,从而再次导致未定义的行为。创建析构函数通常也不是一种解决方案,因为析构函数在许多情况下可能会被调用,例如,在包含相关类作为非静态成员的类的构造函数中。private
我最初建议在这里实现 as 空,并在每个翻译单元中帮助删除调用,但是我没有意识到将可替换的释放函数标记为使程序 IFNDR 等无效。(参见 [replacement.functions]/3。operator delete
inline
inline
您无法删除 ,因为出于我上面提到的原因,它将被 odr 使用,因此必须可行。operator delete
LTO可能进一步帮助在链接过程中摆脱未使用的发出的删除析构函数,至少通过去虚拟化。但我没有测试过。
评论
delete
delete