C++:为什么非虚析构在shared_ptr下能正确释放而unique_ptr却不行

struct Base
{
    ~Base() { std::cout << __FUNCTION__ << endl; }
};

struct Derived : public Base
{
    ~Derived() { std::cout << __FUNCTION__ << endl; }
};

int test()
{
    std::shared_ptr<Base> obj1 = std::make_shared<Derived>();
    std::unique_ptr<Base> obj2 = std::make_unique<Derived>();
}

在开始接触shared_ptr的时候我就发现了这个特性,由于当时对于模板的认知非常一般,故而没有深究。准备一探究竟的时候,搜索到了知乎上的这篇文章,就引用来。

作者:netcan
机械工业出版社《C++20高级编程》作者

原文地址:https://www.zhihu.com/question/432986565

核心在于unique_ptr<Base>只保存了Base类型信息和对应的析构函数;虽然shared_ptr<Base>也是只保存了Base的类型信息,但shared_ptr构造的时候能够拿到具体类型信息Derived*,并存到引用计数块去,引用计数块析构的时候调用的就是子类的析构函数了。

unique_ptr<Base>和手动new/delete管理对象内存方式相比无任何额外开销,实现零成本抽象,不保存额外信息;而shared_ptr因为引用计数的原因导致额外开销,那么可以存储具体类型。

相关细节如下:

先看看std::unique_ptr<Base>,其模板定义和对应的构造函数如下:

template <typename _Tp, typename _Dp = default_delete<_Tp>>
class unique_ptr {
    template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
    explicit unique_ptr(_Tp* __p) noexcept
    : _M_t(__p)
    { }
};

通过构造函数可以发现Derived*被隐式转化成_Tp = Base类型,也就是类型擦除了。而std::shared_ptr<Base>,其模板定义和对应的构造函数如下:

template<typename _Tp>
class shared_ptr : public __shared_ptr<_Tp>
{
    template<typename _Yp, typename = _Constructible<_Yp*>>
    explicit shared_ptr(_Yp* __p) : __shared_ptr<_Tp>(__p) { }
}

通过构造函数可以发现Derived*类型信息被保留到了_Yp = Derived,最终析构的时候就能调用_Yp的构造函数了。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值