Charvak Kondapalli Charvak Kondapalli - 1 year ago 52
C++ Question

C++ destruction order: Calling a field destructor before the class destructor

Is there any way to call a field destructor before the class destructor?

Suppose I have 2 classes

Small
and
Big
, and
Big
contains an instance of
Small
as its field as such:

class Small
{
public:
~Small() {std::cout << "Small destructor" << std::endl;}
};

class Big
{
public:
~Big() {std::cout << "Big destructor" << std::endl;}

private:
Small small;
};

int main()
{
Big big;
}


This, of course, calls the big destructor before the small destructor:

Big destructor
Small destructor


I need the small destructor to be called before the big destructor since it does some cleanup necessary for the big destructor.

I could:


  1. call the
    small.~Small()
    destructor explicitly. -> This, however, calls the small destructor twice: once explicitly, and once after the big destructor has been executed.

  2. have a
    Small*
    as the field and call
    delete small;
    in the big destructor



I am aware that I can have a function in the small class that does the cleanup and call it in the big destructor, but I was wondering if there was a way to inverse the destructor order.

Is there any better way to do this?

Answer Source

call the small.~Small() destructor explicitly. -> This, however, calls the small destructor twice: once explicitly, and once after the big destructor has been executed.

Well, I don't know why you want to keep on with this flawing design, but you can solve the problem described in your first bullet using placement new.
It follows a minimal, working example:

#include <iostream>

struct Small {
    ~Small() {std::cout << "Small destructor" << std::endl;}
};

struct Big {
    Big() { ::new (storage) Small; }

    ~Big() {
        reinterpret_cast<Small *>(storage)->~Small();
        std::cout << "Big destructor" << std::endl;
    }

    Small & small() {
        return *reinterpret_cast<Small *>(storage);
    }

private:
    unsigned char storage[sizeof(Small)];
};

int main() {
    Big big;
}

You don't have anymore a variable of type Small, but with something like the small member function in the example you can easily work around it.

The idea is that you reserve enough space to construct in-place a Small and then you can invoke its destructor explicitly as you did. It won't be called twice, for all what the Big class has to release is an array of unsigned chars.
Moreover, you won't store your Small into the dynamic storage directly, for actually you are using a data member of your Big to create it in.


That being said, I'd suggest you to allocate it on the dynamic storage unless you have a good reason to do otherwise. Use a std::unique_ptr and reset it at the beginning of the destructor of Big. Your Small will go away before the body of the destructor is actually executed as expected and also in this case the destructor won't be called twice.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download