我有大量使用 constexpr 构造函数构造的静态常量对象,因此它们会立即存储在最终二进制文件中,而无需任何构造函数调用。
由于我在低 RAM 系统(STM32 MCU)上工作,我想减少这些对象的内存占用,因为它们是常量,所以将它们存储在 .rodata
部分。编译器毫无问题地解决了这个问题。
但是,现在我向基类添加了一个虚拟析构函数以删除编译器警告,对象存储在 .data
部分。
当然,我可以使用一些 #pragma
专门删除基类的编译器警告并删除虚拟析构函数,但我想知道是否有更清晰的解决方案。
展示问题的极简主义代码:
class Object {
int value;
public:
constexpr Object(int param)
: value(param) {}
virtual int getValue() const = 0;
virtual ~Object() = default; // This line causes problems
};
class Derived : public Object {
volatile int otherValue;
public:
constexpr Derived(int param1, int param2)
: Object(param1), otherValue(param2) {}
int getValue() const override { return otherValue; }
};
const Derived instance(1,2);
int main() {
return instance.getValue();
}
此外,这里有一个 CompilerExplorer,用于比较有无虚拟析构函数:https://godbolt.org/z/M5G7LO
最佳答案
在你声明一个虚方法的那一刻,你就添加了一个非常量指针指向你的类,它指向那个类的虚表。这个指针首先会被初始化为Object的虚表,然后在整个构造函数链中不断变化为派生类的虚指针。然后它将在析构函数链期间再次更改并回滚,直到它指向 Object 的虚拟表。 这意味着您的对象不能再是纯只读对象,必须移出 .rodata。
更简洁的解决方案是省略类中的任何虚函数,或者完全避免继承并使用模板将所需的虚函数调用替换为编译时调用。
关于c++ - 虚拟析构函数将对象移出 rodata 部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57543586/