我正在开发一个程序的嵌入式系统,将不使用动态内存分配。如何防止GCC生成 *deleting析构函数 *(名称中有D0
的析构函数)?它永远不会被召唤。
我认为甚至不需要删除析构函数,因为 *complete object析构函数 *(名称中的D1
)可以沿着operator delete(…)
一起调用。
在我看来,应该有一些命令行选项来禁用这些析构函数。
主要问题是程序在删除析构函数中调用operator delete(…)
。因为我没有任何堆管理,所以没有定义这样的函数。作为一种变通方法,我可以实现只报告错误的operator delete(…)
,但这会浪费内存(不必要的大程序大小),并且不允许我在编译期间捕获对operator delete()
的意外调用。
1条答案
按热度按时间uqjltbpv1#
删除析构函数变量的存在使得语法
其中
ptr
指向多态类型可以工作,即使ptr
没有指向最派生的对象。delete ptr;
的用户不知道最派生的对象的偏移量或其大小是多少,但为了正确调用operator delete
,它需要知道这一点。因此,需要对一个知道的函数进行间接/虚拟调用,即删除析构函数。不幸的是,编译器必须从这样的
virtual
析构函数中生成删除析构函数,至少对于所有用作最派生对象的类,因为在另一个翻译单元中可能存在这种类型的delete
表达式,它不知道这个最派生析构函数的定义,但它必须(间接)调用。我不认为你可以将虚拟析构函数的
delete
行为与执行显式虚拟析构函数调用的能力分开,我也没有看到任何GCC开关来禁用作为非标准/ABI兼容选项的删除析构函数的生成。所以我想你必须避免使用虚拟析构函数。你可以通过从
virtual
函数转发来获得虚拟销毁行为:然后可以使用
ptr->destroy()
来代替ptr->~Base();
/std::destroy_at(ptr)
。然而,这有一个问题,你需要确保
destruct
在每个派生类中都被正确地重写,以避免未定义的行为。CRTP或C++23显式对象参数(显式this
)可能会有所帮助。还有一个问题是,有人可能意外地直接调用析构函数,再次导致未定义的行为。创建析构函数
private
通常也不是一个解决方案,因为析构函数在许多情况下都可能被调用,例如。在一个类的构造函数中,该构造函数包含有问题的类作为非静态成员。我最初在这里建议将
operator delete
实现为空,并在每个转换单元中实现inline
以帮助删除调用,但我没有意识到将可替换的释放函数标记为inline
会使程序IFNDR无效。(参见[替换功能]/3。)你不能删除
operator delete
,因为它将被odr使用,因为我上面提到的原因,因此必须可行。LTO可能会进一步帮助在链接过程中摆脱未使用的删除析构函数,至少通过去虚拟化。但我还没测试过。