0
votes

When an interface contains a pure virtual method, it is recommended to use a virtual destructor. So for example, I have this code:


    template
    class A {
    protected:
        char buffer[Size];
    public:
        virtual void method() = 0;
        A() = default;
        virtual ~A() = default;
    };

    template
    class B : public A {
    public:
        void method() override;
        B() = default
        ~B() = default;
    };

    int main() {
        B b;
        b.method();
    }

But when I try to compile this with g++ for an Arduino Due, I get the following error:


    main.cpp:(.text._ZN4r2d29robot_arm22uarm_gcode_generator_cILj100EED0Ev[_ZN4r2d29robot_arm22uarm_gcode_generator_cILj100EED5Ev]+0x6): undefined reference to `operator delete(void*, unsigned int)'

However, when I remove the destructor from A entirely, it removes the error, but wouldn't this cause Undifed Behaviour? Also, when I just remove the virtual keyword from the destructor of A it gives me the same error message.

1
Are You linking against an implementation of the C++ standard library? stackoverflow.com/q/7015285/1116364Daniel Jour
Note that if I just copy and paste your code into the Arduino Web Editor (after fixing the typos), it compiles just fine there…Michael Kenzel

1 Answers

1
votes

It is rather strange that the sole presence of a destructor would introduce a reference to the global operator delete. However, it seems that you're not the first one with this problem: Undefined reference to 'operator delete(void*)'. As pointed out in the comments there, the C++ standard library is not really available on avr-g++ which is most likely what you're using as well.

All that being said, however, I believe I can offer some relief.

When an interface contains a pure virtual method, it is recommended to use a virtual destructor.

A virtual destructor is only necessary when you need to delete an object via a base pointer [expr.delete]/3. Think of a virtual destructor as part of the interface itself. If an interface declares a virtual destructor, that means "objects that implement this interface can be deleted". The operation delete becomes part of the interface.

If you do not need the capability to delete as part of your interface, which, I would argue, should actually be the default, then you don't need a virtual destructor. Simply declare the destructor non-virtual and make it protected. Thus, you remove the operation delete from the interface and pass on the decision whether a type can be deleted further down to more concrete implementations of the interface…