C++销毁顺序:在类析构函数之前调用字段析构函数
C++ destruction order: Calling a field destructor before the class destructor
有没有办法在类析构函数之前调用字段析构函数?
假设我有 2 个类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
我需要在Big
析构函数之前调用Small
析构函数,因为它会执行Big
析构函数所需的一些清理。
我可以:
- 显式调用
small.~Small()
析构函数。 -> 但是,这会调用Small
析构函数两次:一次显式调用,一次在执行Big
析构函数之后。 - 将
Small*
作为字段并在Big
析构函数中调用delete small;
我知道我可以在Small
类中有一个函数来执行清理并在Big
析构函数中调用它,但我想知道是否有办法反转析构函数顺序。
有没有更好的方法可以做到这一点?
显式调用 small.~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的一部分,因此是否可以使用它主要取决于您必须遵守的标准的修订版。
在不知道为什么要这样做的情况下,我唯一的建议是将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;
};
析构函数调用的顺序无法更改。设计它的正确方法是Small
执行自己的清理。
如果无法更改Small
则可以创建一个包含Small
的类SmallWrapper
,也可以执行所需的清理。
标准容器std::optional
或std::unique_ptr
或std::shared_ptr
可能足以满足此目的。
- 析构函数调用
- 在具有向量的类构造函数中进行析构函数调用
- 从 c++ 中派生类的析构函数调用虚函数
- C++析构函数调用两次,堆栈分配的复合对象
- C++ 在析构函数调用之前删除的动态成员数组
- 析构函数调用c++中的一个向量
- Singleton模式中的手动析构函数调用:调用多次
- 从内部类的析构函数调用虚拟函数
- 与 boost odeint 集成期间的析构函数调用
- 堆栈展开如何与析构函数调用有关?
- C++:优化析构函数调用
- 以逗号分隔的表达式中的析构函数调用
- GCC 9.1 返回 void& 作为显式析构函数调用的结果类型。这是一个错误吗?
- 从C++中的虚拟析构函数调用虚拟方法
- 从指针返回对象时出现意外的析构函数调用
- 使用 decltype 显式析构函数调用
- C++析构函数调用了错误的对象
- 了解虚拟函数和析构函数调用
- 多重继承析构函数调用他自己和父析构函数?c++
- 析构函数调用表单不适当的库