有方法在类析构函数之前调用字段析构函数吗?
假设我有两个类Small和Big,Big包含一个Small实例作为它的字段:
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;
}当然,这在小析构函数之前调用了大析构函数:
Big destructor
Small destructor我需要在Small析构函数之前调用Big析构函数,因为它为Big析构函数做了一些必要的清理。
我可以:
small.~Small()析构函数。但是,->这会调用Small析构函数两次:一次显式调用,一次在执行Big析构函数之后调用。Small*作为字段,并在Big析构函数中调用Big我知道我可以在Small类中有一个函数来进行清理并在Big析构函数中调用它,但是我想知道是否有一种方法可以逆转析构函数的顺序。
有什么更好的方法吗?
发布于 2017-07-26 16:46:08
显式调用等量小。~Small()析构函数。但是,这个->调用小析构函数两次:一次显式调用,一次在执行大析构函数之后调用。
嗯,我不知道你为什么要继续这个完美的设计,但你可以解决你的第一个子弹描述的问题,使用新的位置。
下面是一个最小的工作示例:
#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;
}您不再有一个类型为Small的变量,但是在示例中使用类似于small成员函数的内容,您可以轻松地绕过它。
这样做的想法是,保留足够的空间来构造就地的Small,然后可以像以前那样显式地调用它的析构函数。它不会被调用两次,因为Big类必须发布的是一个unsigned char数组。
此外,您不会将Small直接存储到动态存储中,因为实际上您正在使用Big的一个数据成员来创建它。
尽管如此,我还是建议您在动态存储中分配它,除非您有充分的理由这样做。使用std::unique_ptr并在Big析构函数开始时重置它。在析构函数的主体按预期执行之前,您的Small将消失,而且在这种情况下,析构函数不会被调用两次。
编辑
正如注释中所建议的那样,std::optional可以是另一个可行的解决方案,而不是std::unique_ptr。请记住,std::optional是C++17的一部分,所以如果可以使用它,主要取决于您必须遵守的标准的修订。
发布于 2017-07-26 15:48:53
在不知道为什么要这样做的情况下,我唯一的建议是将Big分解为Small之后需要从其他部分销毁的部分,然后使用组合将其包含在Big中。这样,你就可以控制毁灭的次序。
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;
};发布于 2018-03-11 23:02:09
不能更改析构函数调用的顺序。正确的设计方法是Small执行自己的清理。
如果不能更改Small,则可以创建一个包含Small的类SmallWrapper,并且还可以执行所需的清理。
标准容器std::optional、std::unique_ptr或std::shared_ptr可能足以满足这一目的。
https://stackoverflow.com/questions/45331271
复制相似问题