Gilad Naaman Gilad Naaman - 3 months ago 16
C++ Question

Compiling C++ without the delete operator

I am writing a C++ program for an embedded device, and I want to compile it without libstdc++, exceptions, and dynamic memory allocation.

Example program:

#include <stdio.h>

class A
{
public:
virtual ~A() {}
virtual void Foo() = 0;
};

class B : public A
{
public:
virtual ~B() {}
virtual void Foo() override{}
};

int main()
{
B b;
return 0;
}


Immediately I ran into the following errors.


$ gcc src.cpp -static -fno-rtti -fno-exceptions -std=c++11

/tmp/ccd0Wydq.o: In function
A::~A()':
src.cpp:(.text._ZN1AD2Ev[_ZN1AD5Ev]+0x29): undefined reference to
operator delete(void*)' /tmp/ccd0Wydq.o: In function
A::~A()':
src.cpp:(.text._ZN1AD0Ev[_ZN1AD5Ev]+0x20): undefined reference to
operator delete(void*)' /tmp/ccd0Wydq.o: In function
B::~B()':
src.cpp:(.text._ZN1BD2Ev[_ZN1BD5Ev]+0x35): undefined reference to
operator delete(void*)' /tmp/ccd0Wydq.o: In function
B::~B()':
src.cpp:(.text._ZN1BD0Ev[_ZN1BD5Ev]+0x20): undefined reference to
operator delete(void*)'
/tmp/ccd0Wydq.o:(.rodata._ZTV1A[_ZTV1A]+0x20): undefined reference to
`__cxa_pure_virtual' collect2: error: ld returned 1 exit status
Makefile:2: recipe for target 'all' failed make: *** [all] Error 1


I understand why
__cxa_pure_virtual
is needed, but couldn't for the life of me get why I need a
delete
implementation.

I perform no
new
or
delete
operations in the code, why would it be needed?

When implementing both functions to satisfy the linker's demands, it seems that neither are called (as expected).

Is there a way to avoid implementing these functions?

Answer

When a virtual destructor is called via a delete expression, the operator delete that gets called is determined from the scope of the most-derived class. For example,

#include <iostream>

class Base {
public:
    virtual ~Base() {}
};

void destroy_base(Base* b) { delete b; }

class Derived : public Base {
public:
    static void operator delete(void* ptr) {
        std::cout << "Derived::operator delete\n";
        ::operator delete(ptr);
    }
};

int main() {
    destroy_base( new Derived );
}

prints "Derived::operator delete", even though function destroy_base has no knowledge of class Derived.

g++ implements this by putting two versions of the destructor in every class's vtable: one that just destroys the members and bases, and one that does all that and then calls the appropriate operator delete. This is where your undefined symbols are coming from.

If you never actually use a delete expression, just stub out the ::operator delete function and you should be fine.

Comments