首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++销毁顺序:在类析构函数之前调用字段析构函数

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

Stack Overflow用户
提问于 2017-07-26 15:24:15
回答 3查看 1.8K关注 0票数 6

有方法在类析构函数之前调用字段析构函数吗?

假设我有两个类SmallBigBig包含一个Small实例作为它的字段:

代码语言:javascript
复制
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;
}

当然,这在小析构函数之前调用了大析构函数:

代码语言:javascript
复制
Big destructor
Small destructor

我需要在Small析构函数之前调用Big析构函数,因为它为Big析构函数做了一些必要的清理。

我可以:

  1. 显式调用small.~Small()析构函数。但是,->这会调用Small析构函数两次:一次显式调用,一次在执行Big析构函数之后调用。
  2. Small*作为字段,并在Big析构函数中调用Big

我知道我可以在Small类中有一个函数来进行清理并在Big析构函数中调用它,但是我想知道是否有一种方法可以逆转析构函数的顺序。

有什么更好的方法吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-07-26 16:46:08

显式调用等量小。~Small()析构函数。但是,这个->调用小析构函数两次:一次显式调用,一次在执行大析构函数之后调用。

嗯,我不知道你为什么要继续这个完美的设计,但你可以解决你的第一个子弹描述的问题,使用新的位置。

下面是一个最小的工作示例:

代码语言:javascript
复制
#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的一部分,所以如果可以使用它,主要取决于您必须遵守的标准的修订。

票数 2
EN

Stack Overflow用户

发布于 2017-07-26 15:48:53

在不知道为什么要这样做的情况下,我唯一的建议是将Big分解为Small之后需要从其他部分销毁的部分,然后使用组合将其包含在Big中。这样,你就可以控制毁灭的次序。

代码语言:javascript
复制
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
EN

Stack Overflow用户

发布于 2018-03-11 23:02:09

不能更改析构函数调用的顺序。正确的设计方法是Small执行自己的清理。

如果不能更改Small,则可以创建一个包含Small的类SmallWrapper,并且还可以执行所需的清理。

标准容器std::optionalstd::unique_ptrstd::shared_ptr可能足以满足这一目的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45331271

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档