基类中的非虚析构函数,但派生类中的虚析构函数会导致分段错误 [英] Non virtual destructor in base class, but virtual destructor in derived class cause segmentation fault

查看:213
本文介绍了基类中的非虚析构函数,但派生类中的虚析构函数会导致分段错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近在求职面试中,当基类的析构函数未被声明为虚拟时,我被问及派生类中内存泄漏的问题。

recently in a job interview I was asked about the problem of leaking memory in derived classes when the base class's destructor is not declared virtual.

我写了一个小测试确认我的答案,但我发现了一些有趣的东西。显然,如果您通过 new 创建派生对象,但将其指针存储为 Base * ,如果删除了指针,那么派生对象的析构函数将不会被调用(这对于我对问题的回答非常多)。

I wrote a small test to confirm my answer, but I found something interesting. Obviously, if you create a Derived object via new but store its pointer as a Base*, the derived object's destructor won't be called, if the pointer is deleted (so much for my answer to the question).

I在这种情况下,我认为派生类的析构函数是否是虚拟的是相关的,但在我的系统中,以下代码显示:

I thought whether the derived class's destructor is virtual or not is irelevant in that case, but on my system the following code shows otherwise:

#include <iostream>
#include <string>

// just a helper class, printing its name out when it is destructed
class PrintOnDestruct
{
    public:
        PrintOnDestruct( const std::string& name )
        : name_( name )
        {}

        ~PrintOnDestruct()
        {
            std::cout << "Destructing: " << name_ << std::endl;
        }

    protected:

        std::string name_;
};

// the Base class
class Base
{
    public:
        Base()
        {
            print_on_destruct_ = new PrintOnDestruct( "Base" );
        }

        // the destructor is NOT virtual!
        ~Base()
        {
            delete print_on_destruct_;
        }

    protected:

        PrintOnDestruct* print_on_destruct_;

};

// the NonVirtualDerived class, doesn't have a virtual destructor either
class NonVirtualDerived : public Base
{
    public:
        NonVirtualDerived()
        : Base()
        {
            print_on_destruct_child_ = new PrintOnDestruct( "NonVirtualDerived" );
        }

        // the destructor is NOT virtual!
        ~NonVirtualDerived()
        {
            delete print_on_destruct_child_;
        }

    protected:

        PrintOnDestruct* print_on_destruct_child_;

};

// the VirtualDerived class does have a virtual destructor 
class VirtualDerived : public Base
{
    public:
        VirtualDerived()
        : Base()
        {
            print_on_destruct_child_ = new PrintOnDestruct( "VirtualDerived" );
        }

        // the destructor is virtual!
        virtual ~VirtualDerived()
        {
            delete print_on_destruct_child_;
        }

    protected:

        PrintOnDestruct* print_on_destruct_child_;

};

int main()
{
    // create the two child classes
    Base* non_virtual_derived = new NonVirtualDerived;
    Base* virtual_derived = new VirtualDerived;

    // delete the two objects
    delete non_virtual_derived; // works as expected (only calls Base's destructor, the memory of NonVirtualDerived will be leaked)
    delete virtual_derived; // segfault, after calling Base's destructor

    return 0;
}

我原本期望程序输出以下两行并正常退出:

I would have expected the program to output the following two lines and quit normally:

Destructing: Base
Destructing: Base

我得到了那个输出,但是在第二行之后,程序退出并出现了分段错误。并且消息:

I get that output, but immediately after the second line the program quits with a segmentation fault. And the message:

*** Error in `...': free(): invalid pointer: 0x00000000006020e8 ***

我已将两次调用的顺序更改为 delete ,但程序总是会在调用 delete virtual_derived; 时出现段错误。任何人都可以告诉我为什么会这样吗?

I've changed the order of the two calls to delete, but the programm would always segfault in the call to delete virtual_derived;. Can anybody tell me why this is so?

推荐答案

答案真的在于声明:

    Base* virtual_derived = new VirtualDerived;

您正试图释放'malloc'未返回的地址。要了解原因,请将此行替换为

You are trying to 'free' an address that was not returned by 'malloc'. To understand why, replace this line with

    VirtualDerived* x = new VirtualDerived;
    Base* virtual_derived = x;

如果您打印这两个地址,您会注意到'x'和'virtual_derived'具有不同的值。 'malloc'返回的地址(通过'new')是'x',传递给'free'的地址(通过'delete')是'virtual_derived'。

If you print these two addresses, you will notice that 'x' and 'virtual_derived' have different values. The address that 'malloc' returned (via 'new') is 'x' and the address that was passed to 'free' (via 'delete') is 'virtual_derived'.

这篇关于基类中的非虚析构函数,但派生类中的虚析构函数会导致分段错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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