C ++ destruction order: calling field destructor before class destructor
Is there a way to call the field destructor before the class destructor?
Suppose I have 2 classes Small
and Big
, and Big
contains an instance 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 large destructor before the small destructor:
Big destructor
Small destructor
I need a destructor Small
that is called before the destructor Big
, since it does some of the cleanup required for the destructor Big
.
I could:
- call the destructor
small.~Small()
explicitly. -> This, however, calls the destructorSmall
twice: once explicitly and once after the destructor is executedBig
. - have
Small*
as field and calldelete small;
in destructorBig
I know I may have a class function Small
that does cleanup and calls it in the destructor Big
, but I was wondering if there is a way to invert the order of the destructor.
Is there a better way to do this?
source to share
call small. ~ Small () is a destructor explicitly. -> This, however, calls the small destructor twice: once explicitly and once after the large destructor has been executed.
Well, I don't know why you want to continue with this flawed design, but you can solve the problem described in your first pool using placement new.
This 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 no longer have a type variable Small
, but with something like a member function Small
in this example, you can easily bypass it.
The idea is that you reserve enough space to create in place a Small
, and then you can explicitly call its destructor as you did. It won't be called twice, since all the class has to send Big
is an array unsigned char
s.
Moreover, you won't be storing Small
yours directly in dynamic storage, since you are actually using your item Big
to create it.
That being said, I suggest you allocate it on dynamic storage unless you have a compelling reason to do so. Use std::unique_ptr
and reset at the beginning of the destructor Big
. Yours Small
will disappear before the destructor's body is executed as expected, in which case the destructor will not be called twice.
EDIT
As pointed out in the comments, there std::optional
might be another viable solution instead std::unique_ptr
. Keep in mind that std::optional
is part of C ++ 17, so if you can use it, it mainly depends on which version of the standard you have to stick to.
source to share
Without knowing why you want to do this, my only suggestion is to split Big
into parts to be destroyed after Small
from the rest, and then use composition to include inside Big
. Then you control the order of destruction:
class Small
{
public:
~Small() {std::cout << "Small destructor" << std::endl;}
};
class BigImpl
{
public:
~BigImpl() { std::cout << "Big destructor" << std::endl; }
};
class Big
{
private:
BigImpl bigimpl;
Small small;
};
source to share
The order of calls to the destructor cannot be changed. The correct way to design it is to Small
do its own cleanup.
If you cannot change Small
, then you can create the SmallWrapper
containing class Small
and also do the necessary cleanup.
For this purpose, standard containers std::optional
or std::unique_ptr
or may be sufficient std::shared_ptr
.
source to share