Overloading operator delete in a base class

2019-04-07 22:45发布

问题:

From the C++ standard (ISO/IEC 14882:2003(E)), §12.5.4, about overloading operator delete:

If a delete-expression begins with a unary :: operator, the deallocation function's name is looked up in global scope. Otherwise, if the delete-expression is used to deallocate a class object whose static type has a virtual destructor, the deallocation function is the one found by the lookup in the definition of the dynamic type's virtual destructor (12.4). Otherwise, if the delete-expression is used to deallocate an object of class T or array thereof, the static and dynamic types of the object shall be identical and the deallocation function's name is looked up in the scope of T. If this lookup fails to find the name, the name is looked up in the global scope. If the result of the lookup is ambiguous or inaccessible, or if the lookup selects a placement deallocation function, the program is ill-formed.

§12.5.7 is also interesting:

Since member allocation and deallocation functions are static they cannot be virtual. [Note: however, when the cast-expression of a delete-expression refers to an object of class type, because the deallocation function actually called is looked up in the scope of the class that is the dynamic type of the object, if the destructor is virtual, the effect is the same. For example,

struct B {
    virtual ˜B();
    void operator delete(void*, size_t);
};
struct D : B {
    void operator delete(void*);
};
void f()
{
    B* bp = new D;
    delete bp; // uses D::operator delete(void*)
}

Here, storage for the non-array object of class D is deallocated by D::operator delete(), due to the virtual destructor.]

After reading this, I am wondering...

  • Is this part of the standard fully supported by all major C++ compilers (MSVC++, GCC)?
  • If so, how did they do it? Hidden virtual function? "Special" virtual destructor call? RTTI?
  • Using the example from the standard: can there be problems if f() and D::operator delete() are defined in separate EXE/DLL/DSOs? (Assuming that everything is compiled using the same compiler, of course)

§5.3.5.5 may also be relevant:

In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand's dynamic type and the static type shall have a virtual destructor or the behavior is undefined. In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.

回答1:

I don't know much about VC++ ABI, but the Itanium ABI is well documented.

Looking up at the name mangling scheme, one see:

<ctor-dtor-name> ::= C1     # complete object constructor
                 ::= C2     # base object constructor
                 ::= C3     # complete object allocating constructor
                 ::= D0     # deleting destructor
                 ::= D1     # complete object destructor
                 ::= D2     # base object destructor

Of interest: D0 # deleting destructor, which means that even though delete is non virtual, since it is called from the virtual destructor, it can be considered virtual for all effects and purposes.



回答2:

After dig into the assembly code in emit by GCC 4.8

The GCC will generate two piece of code (for class whose destructor is virtual):

One is assembly snippet#1 for {Destructor + Dealloc}
The other is assembly snippet#2 for {Destructor only}

And for the class whose destructor is not virtual, the call deallocation function instruction will generate in the point where you call delete.

(Following discussion assume the destructor is virtual) So for following code:

delete C   // This will be translate as call snippet#1 for the correct dynamic type

And if you code is following:

p->C::~C()  // this will be translate to call snippet#2

So the deallocate function is bind together with the virtual destructor. So I think this will answere your question about how the deallocate function are implement like virtual but also static.