Why is delete operator required for virtual destructors

Because of deleting destructors. That are functions that are actually called when you call delete obj on an object with virtual destructors. It calls the complete object destructor (which chains base object destructors — the ones that you actually define) and then calls operator delete. This is so that in all places where delete obj is used, only one call needs to be emitted, and is also used to call operator delete with the same pointer that was returned from operator new as required by ISO C++ (although this could be done more costly via dynamic_cast as well).

It's part of the Itanium ABI that GCC uses.

I don't think you can disable this.


In C++20 there is now a fix: P0722R3. The static void operator delete(T*, std::destroying_delete_t) deallocation function. It essentially maps to the destroying destructor.

You can just make it not call ::operator delete, like:

class Base {
public:
    void operator delete(Base* p, std::destroying_delete_t) {
        // Shouldn't ever call this function
        std::terminate();  // Or whatever abort-like function you have on your platform

        // The default implemenation without any overrides basically looks like:
        // p->~Base(); ::operator delete(p);
        // Which is why the call to `operator delete` is generated
    }
    virtual ~Base() {}
};

class Derived : public Base {
public:
    // Calls Base::operator delete in deleting destructor, so no changes needed
    ~Derived() {}
};

int main() {
    Derived d;
}

The deleting destructor is the one called when you do delete ptr_to_obj;. It can only be called by delete expressions, so if you have none in your code, this should be fine. If you do, you can replace them with ::delete ptr_to_obj; and the deleting destructor will no longer be called (it's purpose is to call overriden operator delete's for classes, and ::delete will only call the global ::operator delete)