在销毁派生对象时,调用子类和父类析构函数会出现问题吗?

huangapple go评论152阅读模式
英文:

Are there any issues from both the child and parent destructors being called when a derived object is destroyed?

问题

如果我有以下两个类:

#include <cstdlib>

class Parent
{
    protected:
        int* mem = (int*) std::malloc(5); // 指向动态分配对象的指针
    public:
        Parent() {};
        virtual ~Parent()
        {
            delete(mem);
        }
};

class Child: public Parent
{
    public:
        Child() {};
        ~Child()
        {
            delete(mem);
        }
};

int main(void)
{
    Child* c = new Child();
    delete(c);
}

Child类的实例上调用delete应该会导致分段错误,因为在子类的析构函数之后也会自动调用父类的析构函数吗?如果是这样的话,解决方案是Child类只处理由Child类 "拥有" 的动态分配内存,即不在Child的析构函数中删除mem,而是留给Parent来处理它吗?

我运行了我的主函数并期望出现分段错误,因为mem被释放了两次 - 一次在Child的析构函数中,再一次在Parent的析构函数中。但没有出现错误,这让我感到惊讶。可以有人解释为什么吗?

英文:

If I have the below two classes:

#include &lt;cstdlib&gt;

class Parent
{
    protected:
        int* mem = (int*) std::malloc(5); // pointer to dynamically-stored object
    public:
        Parent() {};
        virtual ~Parent()
        {
            delete(mem);
        }
};

class Child: public Parent
{
    public:
        Child() {};
        ~Child()
        {
            delete(mem);
        }
};

int main(void)
{
    Child* c = new Child();
    delete(c);
}

Shouldn't calling delete on an instance of the Child class cause a segmentation fault, since the parent's destructor is also automatically called after the child destructor? And if so, would the solution be for the Child class to only deal with freeing dynamically-allocated memory "owned" by Child class (i.e. not delete mem in Child's destructor and leave it to Parent to deal with it) ?

I ran my main function and expected a segmentation fault to occur since mem was being freed twice - once in Child's destructor and again in the Parent destructor. No error occurred, which I found surprising. Can anyone please explain why?

答案1

得分: 7

你的代码存在两个问题:

  1. 使用 malloc 分配的内存应该使用 free 释放,而不是 delete
  2. Child 不应尝试释放它没有分配的内存。当 Parent 析构函数执行时,它会尝试释放已被 Child 释放的内存。

这两个问题都会导致未定义行为(Undefined Behavior),这意味着任何事情都可能发生。

英文:

Your code has 2 issues:

  1. Memory allocated with malloc should be released with free, not with delete.
  2. The Child should not attempt to free memory that it did not allocate. When the Parent destructor will execute it will attempt to release memory that was already released by the Child.

Both these issues cause UB (Undefined Behavior), meaning anything can happen.

答案2

得分: 2

问题不在于两个析构函数都被调用,这是设计行为;
问题在于你重复删除指针(双重释放)。

由于你在基类中管理指针,因此基类析构函数负责销毁它是很自然的。尽管还有其他设计方式。
(例如,子类删除指针并将其设置为null,以便后续调用的基类析构函数无法再次删除它,或者完全忘记这一切并使用std::unique_ptr<int>)。

英文:

The problem is not that both destructors are called, which is the designed behavior;
the problem is that you are deleting a pointer twice (double-free).

Since you are managing the pointer in the base class it is natural that only the base destructor is responsible for the destruction.
Although other designs are possible.
(For example, the child deletes de pointers and sets it to null so the base destructor --called later-- cannot delete it again, or really forget about all this an use a std::unique_ptr&lt;int&gt;).

huangapple
  • 本文由 发表于 2023年3月1日 13:09:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/75599793.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定