c++ - 虚拟析构函数将对象移出 rodata 部分

标签 c++ gcc elf

我有大量使用 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/

相关文章:

c++ - 如何在没有波浪号替换的情况下获取真实文件名

c++ - cout 语句如何影响编写的代码的 O/P?

c - 是否应该在每个声明中使用关键字 "inline"?

c - 执行 ELF IFUNC 调度函数时读取环境

gcc - 为什么独立的 C hello 程序在用作动态链接器时会崩溃

c++ - 我可以在浏览器呈现之前访问 Flash 数据吗?

c++ - 使用 libsrtp 编译 asterisk 时出错

c - 为什么 GCC pad 与 NOP 一起起作用?

c++ - "variable tracking"占用了我的编译时间!

c - MSP430 上的 C 程序所需的最大堆栈大小