c++ - C++销毁顺序:在类析构函数之前调用字段析构函数

标签 c++ destructor object-destruction

在类析构函数之前有没有方法调用字段析构函数?
假设我有两个类SmallBigBig包含一个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*作为字段,并在delete small;析构函数中调用Big
我知道我可以在Small类中有一个函数来执行清理并在Big析构函数中调用它,但是我想知道是否有方法来反转析构函数的顺序。
有没有更好的办法?

最佳答案

显式调用small.~small()析构函数。->但是,这将调用小析构函数两次:一次显式调用,一次在执行大析构函数之后调用。
好吧,我不知道你为什么要继续这个有缺陷的设计,但是你可以用Placement New来解决第一个项目中描述的问题。
它遵循一个最小的工作示例:

#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 chars数组。
此外,您不会将Small直接存储到动态存储中,因为实际上您正在使用Big的数据成员创建它。
也就是说,我建议您在动态存储上分配它,除非您有充分的理由这样做。使用std::unique_ptr并在Big的析构函数开始时重置它。您的Small将在析构函数的主体实际按预期执行之前消失,在这种情况下,析构函数不会被调用两次。
编辑
正如评论中所建议的,std::optional可能是另一个可行的解决方案,而不是std::unique_ptr。请记住,std::optional是C++ 17的一部分,所以如果你能使用它,主要取决于你必须遵守的标准的修订。

本文翻译自 https://stackoverflow.com/questions/45331271/

网站遵循 CC BY-SA 4.0 协议,转载或引用请注明出处。


相关文章:

c++ - C ++析构函数总是或者有时只调用数据成员析构函数吗?

c++ - 在容器中使用新放置

javascript - 如何在JavaScript中删除Worker对象?

c++ - 共享库中静态对象的销毁顺序

c++ - 如何开始星期几?

c++ - c ++ 11使用uniform_real_distribution随机双打

c++ - 宏重新定义可以应用于单个cpp文件吗?

c++ - C ++为什么调用此析构函数,它从何而来

c++ - 如何正确释放2D数组C ++

c++ - 仅针对特定条件重置变量的值,并针对其他所有项重置固定值