有没有办法在类析构函数之前调用字段析构函数?
假设我有2个类<audio controls>
<source src="http://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3"</source>
</audio>
<audio controls>
<source src="http://localhost:8080/MyProject/static/music/SoundHelix-Song-1.mp3"></source>
</audio>
和,而
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
析构函数。 - &GT;但是,这会将Big
析构函数调用两次:一次显式,一次执行small.~Small()
析构函数后。Small
作为字段,并在Big
析构函数Small*
醇>
我知道我可以在delete small;
类中有一个函数来执行清理并在Big
析构函数中调用它,但我想知道是否有一种方法可以反转析构函数的顺序
有没有更好的方法呢?
答案 0 :(得分:2)
显式调用small .~Small()析构函数。 - &GT;但是,这会将小析构函数调用两次:一次是显式的,一次是在执行大型析构函数之后。
好吧,我不知道为什么你要继续使用这个瑕疵设计,但是你可以使用新的位置解决你的第一个项目中描述的问题。
它遵循一个最小的工作示例:
#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
s的数组。
此外,您不会直接将Small
存储到动态存储中,因为实际上您正在使用Big
的数据成员来创建它。
话虽这么说,我建议你将它分配给动态存储,除非你有充分的理由不这样做。使用std::unique_ptr
并在Big
的析构函数的开头重置它。在析构函数体实际按预期执行之前,Small
将消失,在这种情况下,析构函数不会被调用两次。
修改强>
正如评论中所建议的那样,std::optional
可以是另一种可行的解决方案而不是std::unique_ptr
。请记住,std::optional
是C ++ 17的一部分,因此如果您可以使用它,那么主要取决于您必须遵守的标准版本。
答案 1 :(得分:1)
在不知道为什么你想要这样做的情况下,我唯一的建议是将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;
};
答案 2 :(得分:0)
无法更改析构函数调用的顺序。设计这个的正确方法是Small
执行自己的清理。
如果您无法更改Small
,则可以创建包含SmallWrapper
的课程Small
,并且还可以执行所需的清理。
标准容器std::optional
或std::unique_ptr
或std::shared_ptr
可能足以达到此目的。