Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Virtual destructor moves object out of rodata section

Tags:

c++

gcc

elf

I have a large number of static constant objects which are constructed with a constexpr constructor, so they are immediately stored in the final binary without any constructor call.

Since I'm working on a low RAM system (STM32 MCU), I want to reduce the memory footprint of these objects and since they are constant, store them in the .rodata section instead. The compiler managed this without a problem.

But, now that I added a virtual destructor to the base class in order to remove compiler warnings, the objects are stored in the .data section instead.

Of course, I could use some #pragma to remove the compiler warnings for the base class specifically and remove the virtual destructor, but I want to know if there is a cleaner solution to this.

Minimalism code showcasing the problem:

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();
}

Also, here is a CompilerExplorer to compare with and without the virtual destructor: https://godbolt.org/z/M5G7LO

like image 852
Rob B. Avatar asked Aug 18 '19 10:08

Rob B.


People also ask

What happens when a destructor is virtual?

A virtual destructor is used to free up the memory space allocated by the derived class object or instance while deleting instances of the derived class using a base class pointer object.

What is the purpose of virtual destructor?

A virtual destructor is used to free the space which is assigned to the object of the derived class while we are trying to delete the instances of the base class using a pointer object of the base class.

How is virtual destructor different from normal destructor?

A normal destructor is set to be just that a normal destructor that the class has implementation for and nowhere else. A virtual destructor can be customized for the task at hand because it can be overriden. So if anywhere you need to change the behavior of the destructor you should make it virtual.

What is the the virtual destructor with example?

Deleting a derived class object using a pointer of base class type that has a non-virtual destructor results in undefined behavior. To correct this situation, the base class should be defined with a virtual destructor. For example, following program results in undefined behavior.


1 Answers

The moment you declare a virtual method, you add a non-constant pointer to your class that points to the virtual table of that class. This pointer will first be initialized to Object's virtual table, and then continue to change to the derived classes' virtual pointers throughout the constructor chain. It will then change again during the destructor chain and roll-back until it points to Object's virtual table. That would mean that your object can no longer be a pure read-only object and must move out of .rodata.

A cleaner solution would either be to omit any virtual function in your classes, or to avoid inheritence entirely and use templates to replace the required virtual function calls with compile time calls.

like image 177
Shloim Avatar answered Sep 22 '22 21:09

Shloim