为什么std :: shared_ptr从基类和派生类中调用析构函数,而delete仅从基类中调用析构函数? [英] Why std::shared_ptr calls destructors from base and derived classes, where delete calls only destructor from base class?

查看:378
本文介绍了为什么std :: shared_ptr从基类和派生类中调用析构函数,而delete仅从基类中调用析构函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当第二个示例仅从基类调用析构函数时,为什么使用std :: shared_ptr释放时从基类和派生类调用析构函数?

Why when using std::shared_ptr deallocation calls destructors from both base and derived classes when second example calls only destructor from base class?

class Base
{
public:
    ~Base()
    {
        std::cout << "Base destructor" << std::endl;
    }
};

class Derived : public Base
{
public:
    ~Derived()
    {
        std::cout << "Derived destructor" << std::endl;
    }
};

void virtual_destructor()
{
    {
        std::cout << "--------------------" << std::endl;
        std::shared_ptr<Base> sharedA(new Derived);
    }

    std::cout << "--------------------" << std::endl;
    Base * a = new Derived;
    delete a;
}

输出:

--------------------
Derived destructor
Base destructor
--------------------
Base destructor

我期望两种情况下的行为相同。

I was expecting the same behaviour in both cases.

推荐答案

删除a 是不确定的行为,因为类 Base 没有虚拟析构函数,并且完整对象为 * a (更准确地说:包含 * a 的最派生对象)的类型不是 Base

delete a is undefined behaviour, because the class Base does not have a virtual destructor and the "complete object" of *a (more accurately: the most-derived object containing *a) is not of type Base.

共享的指针是使用推导的删除程序创建的,该删除程序删除派生的* ,因此一切正常。

The shared pointer is created with a deduced deleter that deletes a Derived *, and thus everything is fine.

(推断出的删除器的作用是说删除static_cast< Derived *>(__ the_pointer))。

(The effect of the deduced deleter is to say delete static_cast<Derived*>(__the_pointer)).

如果要使用共享指针重现未定义的行为,则必须立即转换指针:

If you wanted to reproduce the undefined behaviour with the shared pointer, you'd have to convert the pointer immediately:

// THIS IS AN ERROR
std::shared_ptr<Base> shared(static_cast<Base*>(new Derived));

从某种意义上说,这是共享指针行为的正确方法:由于您是已经为类型删除的删除器和分配器支付了虚拟查找的价格,这很公平,您不必为析构函数的另一个虚拟查找支付费用。被类型删除的删除器会记住完整的类型,因此不会产生更多开销。

In some sense, it is The Right Way for the shared pointer to behave: Since you are already paying the price of the virtual lookup for the type-erased deleter and allocator, it is only fair that you don't then also have to pay for another virtual lookup of the destructor. The type-erased deleter remembers the complete type and thus incurs no further overhead.

这篇关于为什么std :: shared_ptr从基类和派生类中调用析构函数,而delete仅从基类中调用析构函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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