为什么std :: shared_ptr从基类和派生类中调用析构函数,而delete仅从基类中调用析构函数? [英] Why std::shared_ptr calls destructors from base and derived classes, where delete calls only destructor from base class?
问题描述
当第二个示例仅从基类调用析构函数时,为什么使用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屋!