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
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With