加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 在物体破坏时留下“僵尸”旗帜

发布时间:2020-12-16 10:32:26 所属栏目:百科 来源:网络整理
导读:我想显式地销毁一个对象(调用它上面的析构函数及其所有字段),但是我可能会发现仍然有一些指向该对象的指针.因此,我不想释放记忆;相反,我想留下一种标志“我是一个被摧毁的对象”. 我想到了以下方法: class BaseClass { //all objects in question derive fr
我想显式地销毁一个对象(调用它上面的析构函数及其所有字段),但是我可能会发现仍然有一些指向该对象的指针.因此,我不想释放记忆;相反,我想留下一种标志“我是一个被摧毁的对象”.

我想到了以下方法:

class BaseClass { //all objects in question derive from this class
public:
    BaseClass() : destroyed(false) {}
    virtual ~BaseClass() {}
private:
    bool destroyed;
public:
    bool isDestroyed() { return destroyed; }
    void destroy() {
        this->~BaseClass(); //this will call the virtual destructor of a derivative class
        new(this) BaseClass();
        destroyed=true;
    }
};

当调用destroy时,我基本上会破坏我拥有的任何物体(也许是衍生物)并在同一个地方创建一个新的“僵尸”.因此,我希望实现:

>之前指向此对象的任何其他指针ptr仍然可以调用ptr-> isDestroyed()来验证其存在.
>我知道如果我不检查僵尸的标志并尝试访问属于任何派生对象的字段,可能会发生不好的事情
>我知道僵尸对象仍然消耗与被破坏对象一样多的内存(因为它可能是BaseClass的衍生物)
>我仍然需要释放被破坏物体的记忆.但是我希望调用删除仍然正确吗?

问题:

使用上述模式时是否还有其他问题需要考虑?

在僵尸对象上调用delete会正确地释放前一个(普通)对象消耗的整个内存吗?

虽然我很感激您对如何以不同方式进行操作的意见,我可能倾向于按照您的方式进行操作 – 我仍然希望了解上述代码带来的所有风险.

解决方法

你对你的问题有一些讨厌的评论.现在我不认为他们是应得的,尽管可能有更好的方法来做你想要的.我知道你来自哪里,但实际上你使用的是析构函数,就像使用你拒绝写的重置函数一样.实际上你从调用析构函数中得不到什么,因为调用析构函数与实际删除或重置任何东西无关,除非你实际编写代码在析构函数中执行它.

至于您关于新展示位置的问题:

您可能已经知道,placement new不会分配任何内存,因此调用它只会在同一个地方创建对象.我明白这正是你想要的,但它不是必需的.由于你没有在对象上调用delete只是destroy,你可以在不初始化类的情况下将destroy设置为true.

把它们加起来:

>如果您将析构函数用作常规虚函数,则什么也得不到.不要这样做,因为如果两次调用析构函数你会遇到麻烦
>对placement new的调用不会分配内存,只是执行不必要的初始化.你可以将destroy设置为true.

要执行您想要正确执行的操作并获得析构函数的好处,您应该重载类的new和delete操作符并使用正常的销毁机制.然后,您可以选择不释放内存,但将其标记为无效或可能释放大部分内存,但将指针指向某些标记.

编辑

在评论之后,我决定总结我看到的所有风险以及其他人指出的风险:

>在多线程环境中访问无效指针:使用您的方法,可以在析构函数运行之后但在设置销毁标志之前访问类(关于您在其中一条注释中的问题 – shared_ptr对于大多数用途是线程安全的)
>中继你不完全控制的行为:你的方法依赖于析构函数自动调用其他未动态分配的成员的析构函数的方式:这意味着你仍然必须释放动态分配内存,你无法控制如何实现这一点,您无法控制调用其他析构函数的顺序.
>转发你并不完全控制的行为(第2点):你正在转发编译器实现析构函数部分的方式,这个析构函数调用其他析构函数,你无法判断你的代码是否可移植,甚至将如何它处理两次调用它.
>可以调用两次析构函数:根据您的实现,这可能会导致内存泄漏或堆损坏,除非您防止两次释放相同的内存.您声称通过调用新的位置来防范这种情况 – 但是在多线程环境中,这不能保证更多的假设所有内存分配都是由默认构造函数完成的 – 这取决于您的具体实现,这可能是也可能不是真正.
>你反对每个回答你问题或对其发表评论的人的更好的判断 – 你可能会遇到一些天才,但很可能你只是通过将你的实现限制在一小部分可以工作的情况下来自我攻击正确.就像使用错误的螺丝刀一样,最终会损坏螺丝.以同样的方式使用语言构造它不打算使用可能最终导致错误的程序 – 析构函数旨在从删除和编译器生成的代码中调用以清除堆栈.直接使用它并不明智.

我重复我的建议 – 重载删除和新的你想要的

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读