Search code examples
c++classobjectdestructor

Custom destructor x default constructors in C++


I have a class with four member and no implemented Destructor by my part. If I delete the object, the 4 members will be deleted by the default destructor, right? If I make a blank custom destructor none of them will be deleted?If I make a custom destructor that only deletes one of them, will the other three be deleted as well?


Solution

  • Strictly answering your questions

    I don't think that answering your question actually helps you because the way you framed the problem doesn't help you. But here it is anyway:

    If I delete the object, the 4 members will be deleted by the default constructor, right?

    Right

    If I make a blank custom destructor none of them will be deleted

    Incorrect. Still all the members will be properly deleted.

    If I make a custom destructor that only deletes one of them, will the other three be deleted as well?

    A destructor (nor any method) cannot legally explicitly delete its own members.

    Addressing your confusion

    If p is a pointer, when you do delete p you are not deleting the pointer p, you are deleting the object pointed by p. p is there to tell you what object needs deletion. After delete p p is still alive. Sure it points to invalid memory, but it itself is not deleted. You can assign to it and make it point to something else.

    Let's consider a simple class with 3 members: a float, an int pointer, and a std::vector object:

    struct X
    {
       float f;
       int* p;
       std::vector<double> v;
    };
    

    The 3 members of your class are: a float, a pointer and std::vector object. These members will always get properly destroyed by the destructor, regardless if you have a user defined destructor or a implicit destructor. Always! All members! No exception. You cannot inhibit or modify this behavior in any way.

    For f I don't think there is anything to explain.

    Now for the interesting part: p here you need to see a very important distinction: the pointer p (which is your data member) and the potential int object that is pointed by p. Like any other data members, the pointer p will properly be disposed by the destructor.

    But what should happen to the object that is pointed by the pointer p? Well there are several cases: your pointer might point to an int object, to null, be uninitialized or point to an invalid address. If it points to an int object it might point to an int object that is a subobject of another class type, it might be an element in an array, it might be an static object or an object with automatic storage duration or it might be an int object created by new. If it is created by new it might be the X class responsibility to delete it or not and there might be a complex decision if it must destroy it (think shared pointers). X should delete the object pointed by p iff X has ownership over this pointer and a proper logic should be implemented.

    As you can see the complier cannot possibly know to what p points to and if X should delete it. That's why the default destructor doesn't do it.

    For v again, the destructor (default or user defined) will properly destroy v. You might now that internally std::vector has a pointer member of its own, but: it's std::vector's responsibility to destroy the array that pointer might point to, not X. It all works out of the box, X does not need to do anything special.

    How you should think about it

    In C++ there is the RAII principle which, despite its poor name it is one of the most important concepts in C++. Basically if your class acquires a resource that needs manual management then that class has ownership over that resource and is it responsible to release that resource. So if your class does manual memory allocation (new) then it is responsible to call the corresponding delete. If it acquires a resource by a fictitious resource_aquire() then it is the one responsible to also call the accompanying resource_destroy()

    Another important principle is the single responsibility principle: if your class is responsible with managing a resource then that class should do only that thing.