Is destructor called implicitly in a overloaded operator delete function?
Asked Answered
W

3

9

I have class Item which defines its own operator new and operator delete as follows:

class Item
{
public:
    Item(const std::string &s):msg(s)
    {
        std::cout<<"Ctor: "<<msg<<std::endl;
    }
    static void* operator new(size_t size, int ID, const std::string &extra)
    {
        std::cout<<"My Operator New. ID/extra: "<<ID<<"/"<<extra<<std::endl;
        return ::operator new(size);
    }
    static void operator delete(void* p)
    {
        std::cout<<"My Operator Delete"<<std::endl;
        return;
    }
    ~Item()
    {
        std::cout<<"Destructor: "<<msg<<std::endl;
    }
    void Print()
    {
        std::cout<<"Item::msg: "<<msg<<std::endl;
    }
private:
    std::string msg;
};

I create an object of this type by using a placement new and then delete as follows:

int main()
{
    Item *pI=new(1,"haha")Item("AC Milan");
    std::cout<<"before delete"<<std::endl;
    delete pI;
    std::cout<<"after delete"<<std::endl;
    return 0;
}

The output is:

My Operator New. ID/extra: 1/haha
Ctor: AC Milan
before delete
Destructor: AC Milan
My Operator Delete
after delete

As you can see, delete pI calls my own delete function in which nothing is done except outputting a log. However, from the output, the destructor of Item is called in delete pI which isn't invoked in my own delete function.

So in this case, destructor would be called implicitly in a overloaded delete function?

Wargo answered 21/11, 2016 at 9:50 Comment(7)
I'm using g++ 4.9.3Wargo
It's the same for both your new and your delete operators. You don't call the constructor in your overloaded new operator either, and it is still called. The constructors and destructors are always called when using the new and delete operators.Circumferential
Memory allocation and object creation/destruction are two separate things. Overloading the allocation functions only affects the former; the latter is controlled entirely by the core language rules.Weintrob
Interestingly MSVC2015 issues a warning: warning C4291: 'void *Item::operator new(std::size_t,int,const std::string &)': no matching operator delete found; memory will not be freed if initialization throws an exception.Petepetechia
@Someprogrammerdude I think constructor would be called by global operator new that is called in my own operator newWargo
@Wargo The global ::operator new function only allocates memory. That you don't have to specify class or type is a clear hint.Circumferential
@Someprogrammerdude. You are right. I checked some documentations and found that constructor would be called anyway after operator new is completed no matter this function is overloaded or not. Thank youWargo
N
7

So in this case, destructor would be called implicitly in a overloaded delete function?

Yes. For a delete expression, (1)the destructor will be invoked firstly, then (2)the apporiate operator delete will be invoked; name lookup and overload resolution will be performed at this stage.

If expression is not a null pointer, the delete expression invokes the destructor (if any) for the object that's being destroyed, or for every element of the array being destroyed (proceeding from the last element to the first element of the array).

After that, unless the matching new-expression was combined with another new-expression (since C++14) the delete expression invokes the deallocation function, either operator delete (for the first version of the expression) or operator delete[] (for the second version of the expression).

Nyala answered 21/11, 2016 at 9:54 Comment(0)
P
3

The destructor is not called by an overloaded operator delete() function.

However, a delete expression (in your case, delete pI) has the effect of first invoking the destructor for the object, and then calling the appropriate overload of operator delete().

Psalmist answered 21/11, 2016 at 10:51 Comment(0)
C
0

So in this case, destructor would be called implicitly in a overloaded delete function?

Destructors and overloaded delete operators interact in a complicated way. When you say

delete pI;

this actually compiles to an invocation of your destructor, and no reference is made to "delete".

Your destructor has (GCC) two instances in the VTable (if virtual), or (MSVC) a boolean argument. The instances / bool are used to determine whether the destructor so compiled should be a deleting, or a non-deleting destructor call. As you can guess, the deleting destructor is then responsible for calling the link-time operator delete for you. If you'd have written

pI->~Item();

you would have compiled to running the non-deleting destructor (the other vtable entry, or with the boolean flipped).

Since your destructor is nonvirtual, it's probably all inlined anyway. The behaviour will be indistinguishable from this though. This is how, if your destructor is virtual, the delete will invoke the right delete for whatever type you actually have, rather than the delete of the pointer type on which you call delete.

Cosmography answered 21/11, 2016 at 10:38 Comment(1)
For completeness, there's a third destructor, that's used to destruct your class but not your virtual bases. It's not relevant in this discussion, as you have no virtual bases.Cosmography

© 2022 - 2024 — McMap. All rights reserved.