C ++破坏顺序:在类析构函数之前调用字段析构函数 [英] C++ destruction order: Calling a field destructor before the class destructor

查看:124
本文介绍了C ++破坏顺序:在类析构函数之前调用字段析构函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法在类析构函数之前调用字段析构函数?

Is there any way to call a field destructor before the class destructor?

假设我有2个类, Small Big ,以及 Big 包含 Small 的实例

Suppose I have 2 classes Small and Big, and Big contains an instance of Small as its field as such:

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;
}

当然,这在小析构函数之前称为大析构函数:

This, of course, calls the big destructor before the small destructor:

Big destructor
Small destructor

我需要在 Big 析构函数之前调用 Small 析构函数 Big 析构函数必须进行一些清理。

I need the Small destructor to be called before the Big destructor since it does some cleanup necessary for the Big destructor.

我可以:


  1. 称呼小号。 〜Small()析构函数。 ->但是,这两次调用 Small 析构函数:一次显式,一次执行 Big 析构函数后

  2. 具有 Small * 作为字段,并调用删除small; Big 析构函数

  1. call the small.~Small() destructor explicitly. -> This, however, calls the Small destructor twice: once explicitly, and once after the Big destructor has been executed.
  2. have a Small* as the field and call delete small; in the Big destructor

中,我知道我可以在 Small 类进行清理并在 Big 析构函数中调用它,但我想知道是否有办法

I am aware that I can have a function in the Small class that does the cleanup and call it in the Big destructor, but I was wondering if there was a way to inverse the destructor order.

还有什么更好的方法吗?

Is there any better way to do this?

推荐答案


显式调用small。〜Small()析构函数。 ->但是,这两次调用了小型析构函数:一次是显式调用,一次是在大型析构函数执行之后。

call the small.~Small() destructor explicitly. -> This, however, calls the small destructor twice: once explicitly, and once after the big destructor has been executed.

我不知道您为什么要继续使用这个有缺陷的设计,但是您可以使用new放置来解决第一个项目符号中描述的问题

工作示例:

Well, I don't know why you want to keep on with this flawing design, but you can solve the problem described in your first bullet using placement new.
It follows a minimal, working example:

#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 成员函数,您可以轻松解决该问题。

You don't have anymore a variable of type Small, but with something like the small member function in the example you can easily work around it.

这个想法是,您保留了足够的空间来就地构建 Small ,然后可以像您一样显式调用其析构函数。它不会被调用两次,因为 Big 类必须释放的是一个 unsigned char s数组。 。

而且,您不会将 Small 直接存储到动态存储中,因为实际上您是在使用<$ c $的数据成员c> Big 来创建它。

The idea is that you reserve enough space to construct in-place a Small and then you can invoke its destructor explicitly as you did. It won't be called twice, for all what the Big class has to release is an array of unsigned chars.
Moreover, you won't store your Small into the dynamic storage directly, for actually you are using a data member of your Big to create it in.

话虽如此,我建议您除非有充分的理由,否则在动态存储上分配它。使用 std :: unique_ptr 并将其重置在 Big 的析构函数的开头。您的 Small 将在析构函数的主体按预期执行之前消失,并且在这种情况下,析构函数也不会被调用两次。

That being said, I'd suggest you to allocate it on the dynamic storage unless you have a good reason to do otherwise. Use a std::unique_ptr and reset it at the beginning of the destructor of Big. Your Small will go away before the body of the destructor is actually executed as expected and also in this case the destructor won't be called twice.

编辑

如评论中所建议, std :: optional 可能是另一个可行的解决方案,而不是 std :: unique_ptr 。请记住, std :: optional 是C ++ 17的一部分,因此,是否可以使用它主要取决于您必须遵守的标准修订版本。

As suggested in the comments, std::optional can be another viable solution instead of std::unique_ptr. Keep in mind that std::optional is part of the C++17, so if you can use it mostly depends on what's the revision of the standard to which you must adhere.

这篇关于C ++破坏顺序:在类析构函数之前调用字段析构函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆