英文:
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 <cstdlib>
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
你的代码存在两个问题:
- 使用
malloc
分配的内存应该使用free
释放,而不是delete
。 Child
不应尝试释放它没有分配的内存。当Parent
析构函数执行时,它会尝试释放已被Child
释放的内存。
这两个问题都会导致未定义行为(Undefined Behavior),这意味着任何事情都可能发生。
英文:
Your code has 2 issues:
- Memory allocated with
malloc
should be released withfree
, not withdelete
. - The
Child
should not attempt to free memory that it did not allocate. When theParent
destructor will execute it will attempt to release memory that was already released by theChild
.
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<int>
).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论