Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the delete operator required to be static?

I found this one question asking the same thing, however only the 'new' part was answered, so here goes again.

Why is the delete operator required to be static? Somehow it doesn't make sense. The new operator makes perfect sense, just like the constructor can't be virtual, neither can the new operator. However, the destructor can (and should) be virtual when you use inheritance, in order to allow destruction of objects being used (by way of polymorphism) as a base class.

I understand that, when the delete operator is called, the object has already been destroyed, so no 'this' exists. Yet it still makes sense, using the same reasoning as with virtual destructor, to have the delete operator match the new operator which created the object.

This is what I mean

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

class B : public A
{
  public:
    void* operator new (size_t sz);
    void  operator delete (void* ptr, size_t sz);
};

now if we do

A *ptr = new B();
delete ptr; // <-- fail

A's delete operator (default) should've been called, since it's static and it's not known (for anything but the trivial case here) at compile time which delete-operator is the correct one.

However, I made a small test program with the code above (just malloc/free in the new/delete operators, and print statement in delete), and compiled it using g++. Running it quite unexpectedly produced the output in B's delete operator.

My (real) question is this: Is there some implicit 'virtualness' to the delete operator? Is it only static in the no-this-pointer sense? Or is this just a g++ feature?

I started looking through the C++ specification, but I must admit, I was bit overwhelmed by it, so any help appreciated.

like image 853
falstro Avatar asked Feb 16 '10 13:02

falstro


2 Answers

The answer in the language rules is really in 12.5 [class.free].

If you are deleting via a pointer to a base class then the destructor must be virtual or you get undefined behaviour. Otherwise, the implementation has to determine the dynamic type of the object being deleted.

12.5/4 says that when the delete isn't prefixed by :: then the deallocation function is determined by looking up delete in the context of the dynamic type's virtual destructor. This ensures virtual-like lookup, even though operator delete is always a static member function.

Raw allocation and deallocation happen conceptually outside of the object's lifetime so by the time the deallocation function is to be called, there is no longer an object to provide a virtual lookup mechanism but the lookup rules ensure that operator delete has a dynamic (virtual-lite!) lookup mechanism. This means that operator delete can sensibly be static without losing touch with the original object's dynamic type.

like image 144
CB Bailey Avatar answered Oct 08 '22 05:10

CB Bailey


delete operator is for deallocating memory only, and memory is deallocated for the most derived class object as a whole - in one action - exactly the same way as with new operator it is allocated for the whole most-derived class object - the object of class passed as argument into new Class construct.

This is why when you do delete ptr; the delete operator is always called only once for the actual most-derived class of the object being deleted and the data on what class it is is deduced from either the vtable if the virtual destructor is present or the type of the pointer if there's no virtual destructor. That's why there'no implicit virtualness to the delete operator - all virtualness ends at the point of destructor call.

like image 21
sharptooth Avatar answered Oct 08 '22 04:10

sharptooth