This compiles gracefully:
class dummy {
};
This complains about undefined reference to _sbrk:
class dummy {
virtual ~dummy();
};
Why virtual method generates undefined reference to _sbrk
?
I used to think that vtable
is allocated somewhere statically and does not requre malloc
.
Compiler: arm-none-eabi-gcc 8.0.0
with recent newlib
. Compiled with -fno-rtti -fno-exceptions -fno-unwind-tables
.
Test program (boot
is like main
):
class base {
public:
virtual ~base();
};
class dummy : public base {
public:
~dummy();
};
base::~base() {
__BKPT();
}
dummy::~dummy() {
__BKPT();
}
extern "C" void _sbrk() {
__BKPT();
}
void boot() {
for(;;) {
base b;
dummy d;
}
return 0;
}
Derived classes could have their own delete operator. This feature is very rarely used - almost never in my experience. A virtual destructor allows the correct operator delete to be called when the delete expression is used (delete p
).
The compiler certainly generated a virtual destructor-with-delete that calls the class specific operator delete, which in almost all cases happens to be the global operator delete (::operator delete
) but that can also be overridden by a local operator defined in the class.
Because delete
is never used (for that particular type), that destructor-with-delete automatically generated virtual function is never called, but it is still referenced in the vtable. Unless you have appropriate compiler and linker support, every virtual function is referenced in the vtable and the vtable is used at least in constructors of the class, so any constructed object is going to need every virtual function of that class.
If you have appropriate linker support, you can only bring in virtual functions that are named; other vtable entries can be null as they are never referenced.
EDIT: The standard quote
From [class.dtor]/12:
At the point of definition of a virtual destructor (including an implicit definition), the non-array deallocation function is determined as if for the expression
delete this
appearing in a non-virtual destructor of the destructor's class (see [expr.delete]). If the lookup fails or if the deallocation function has a deleted definition, the program is ill-formed. [ Note: This assures that a deallocation function corresponding to the dynamic type of an object is available for the delete-expression ([class.free]). — end note ]
"virtual destructor" ... determined as if a "non virtual destructor" contained an expression is a verbiage that may be hard to decode: since the destructor is virtual, why are we talking about a virtual destructor? (I had to read the above standard text several times.)
Another way to view is it is, in term of a possible implementation (some implementations used to do exactly that):
Each destructor actually takes a bool parameter deallocate
and compiler adds code:
if (deallocate)
delete this;
just before the end of the body of the destructor, and all destructors are called with a false
argument except the one of the complete object when the delete
operator is invoked.