std::shared_ptr<void> 为什么可以正常调用类的析构

测试代码
#include <stdio.h>
#include <memory>

class CTest {
public:
    CTest() { printf("%s()\n", __func__); }
    ~CTest() { printf("%s()\n", __func__); }
};


int main(int argc, char **argv)
{
    std::shared_ptr<void> ptr(new CTest);
    return 0;
}
测试结果

在这里插入图片描述
通过测试可见,正常调用析构函数了。我们可以思考一个问题,就是模板参数是void,但是问什么可以调用到CTest的析构呢。

我们以以下代码为例子

#include <iostream>
#include <memory>

class CTest {
public:
    CTest() { printf("%s()\n", __func__); }
    ~CTest() { printf("%s()\n", __func__); }
};

int main(int argc, char **argv)
{
    void *ptr = new CTest;
    delete ptr;
    return 0;
}

测试结果
在这里插入图片描述
从测试结果看,delete虽然释放了CTest的内存,但是未调用~CTest,所以shared_ptr可以正常调用到析构一定是shared_ptr做了某些操作。

注意:以下shared_ptr均为linux下源代码

// shared_ptr继承自__shared_ptr,所以直接看__shared_ptr代码
template<typename _Tp>
class shared_ptr : public __shared_ptr<_Tp> {}

// _Lock_policy无关紧要,是防止冲突手段,包括原子,锁和单线程(即无锁无原子操作),默认是原子
template<typename _Tp, _Lock_policy _Lp>
class __shared_ptr : public __shared_ptr_access<_Tp, _Lp> {}

// 接下来看__shared_ptr构造函数
// 常用的就下面几个函数
constexpr __shared_ptr() noexcept // 无参数的默认构造
    : _M_ptr(0), _M_refcount()
{ }

template<typename _Yp, typename = _SafeConv<_Yp>>
explicit __shared_ptr(_Yp* __p) // 传入指针的有参构造
    : _M_ptr(__p), _M_refcount(__p, typename is_array<_Tp>::type())
{
    static_assert( !is_void<_Yp>::value, "incomplete type" );
    static_assert( sizeof(_Yp) > 0, "incomplete type" );
    // 以上可以确定_Yp类型不是void
    _M_enable_shared_from_this_with(__p);
}

template<typename _Yp, typename _Deleter, typename = _SafeConv<_Yp>>
__shared_ptr(_Yp* __p, _Deleter __d) // 可以传入删除器的有参构造
	: _M_ptr(__p), _M_refcount(__p, std::move(__d))
{
	static_assert(__is_invocable<_Deleter&, _Yp*&>::value,
		"deleter expression d(p) is well-formed");
	_M_enable_shared_from_this_with(__p);
}

// 从以上来看,构造函数多了一个模板参数_Yp,这个就是真正的指针类型
// _M_refcount是__shared_count<_Lp>类型(_Lp是_Lock_policy),由它进行内存管理
// 而此时传进去的指针类型也是_Yp*,所以在__shared_ptr析构时,其实__shared_count进行的内存释放,故可以正确的调用对应类型的析构

__shared_count整理出来

template <_Lock_policy _Lp>
class __shared_count
{
public:
    constexpr __shared_count() noexcept : _M_pi(0)
    {
    }

    template <typename _Ptr>
    explicit __shared_count(_Ptr __p) : _M_pi(0)
    {
        __try
        {
            _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);
        }
        __catch(...)
        {
            delete __p;
            __throw_exception_again;
        }
    }

    template <typename _Ptr>
    __shared_count(_Ptr __p, /* is_array = */ false_type)
        : __shared_count(__p)
    {
    }

    template <typename _Ptr>
    __shared_count(_Ptr __p, /* is_array = */ true_type)
        : __shared_count(__p, __sp_array_delete{}, allocator<void>())
    {
    }

    template <typename _Ptr, typename _Deleter>
    __shared_count(_Ptr __p, _Deleter __d)
        : __shared_count(__p, std::move(__d), allocator<void>())
    {
    }

    template <typename _Ptr, typename _Deleter, typename _Alloc>
    __shared_count(_Ptr __p, _Deleter __d, _Alloc __a) : _M_pi(0)
    {
        typedef _Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp> _Sp_cd_type;
        __try
        {
            typename _Sp_cd_type::__allocator_type __a2(__a);
            auto __guard = std::__allocate_guarded(__a2);
            _Sp_cd_type *__mem = __guard.get();
            ::new (__mem) _Sp_cd_type(__p, std::move(__d), std::move(__a));
            _M_pi = __mem;
            __guard = nullptr;
        }
        __catch(...)
        {
            __d(__p); // Call _Deleter on __p.
            __throw_exception_again;
        }
    }

    template <typename _Tp, typename _Alloc, typename... _Args>
    __shared_count(_Sp_make_shared_tag, _Tp *, const _Alloc &__a,
                    _Args &&...__args)
        : _M_pi(0)
    {
        typedef _Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp> _Sp_cp_type;
        typename _Sp_cp_type::__allocator_type __a2(__a);
        auto __guard = std::__allocate_guarded(__a2);
        _Sp_cp_type *__mem = __guard.get();
        ::new (__mem) _Sp_cp_type(std::move(__a),
                                    std::forward<_Args>(__args)...);
        _M_pi = __mem;
        __guard = nullptr;
    }


    // Special case for unique_ptr<_Tp,_Del> to provide the strong guarantee.
    template <typename _Tp, typename _Del>
    explicit __shared_count(std::unique_ptr<_Tp, _Del> &&__r) : _M_pi(0)
    {
        // _GLIBCXX_RESOLVE_LIB_DEFECTS
        // 2415. Inconsistency between unique_ptr and shared_ptr
        if (__r.get() == nullptr)
            return;

        using _Ptr = typename unique_ptr<_Tp, _Del>::pointer;
        using _Del2 = typename conditional<is_reference<_Del>::value,
                                            reference_wrapper<typename remove_reference<_Del>::type>,
                                            _Del>::type;
        using _Sp_cd_type = _Sp_counted_deleter<_Ptr, _Del2, allocator<void>, _Lp>;
        using _Alloc = allocator<_Sp_cd_type>;
        using _Alloc_traits = allocator_traits<_Alloc>;
        _Alloc __a;
        _Sp_cd_type *__mem = _Alloc_traits::allocate(__a, 1);
        _Alloc_traits::construct(__a, __mem, __r.release(),
                                    __r.get_deleter()); // non-throwing
        _M_pi = __mem;
    }

    // Throw bad_weak_ptr when __r._M_get_use_count() == 0.
    explicit __shared_count(const __weak_count<_Lp> &__r);

    // Does not throw if __r._M_get_use_count() == 0, caller must check.
    explicit __shared_count(const __weak_count<_Lp> &__r, std::nothrow_t);

    ~__shared_count() noexcept
    {
        if (_M_pi != nullptr)
            _M_pi->_M_release();
    }

    __shared_count(const __shared_count &__r) noexcept
        : _M_pi(__r._M_pi)
    {
        if (_M_pi != 0)
            _M_pi->_M_add_ref_copy();
    }

    __shared_count &operator=(const __shared_count &__r) noexcept
    {
        _Sp_counted_base<_Lp> *__tmp = __r._M_pi;
        if (__tmp != _M_pi)
        {
            if (__tmp != 0)
                __tmp->_M_add_ref_copy();
            if (_M_pi != 0)
                _M_pi->_M_release();
            _M_pi = __tmp;
        }
        return *this;
    }

    void _M_swap(__shared_count &__r) noexcept
    {
        _Sp_counted_base<_Lp> *__tmp = __r._M_pi;
        __r._M_pi = _M_pi;
        _M_pi = __tmp;
    }

    long _M_get_use_count() const noexcept
    {
        return _M_pi != 0 ? _M_pi->_M_get_use_count() : 0;
    }

    bool _M_unique() const noexcept
    {
        return this->_M_get_use_count() == 1;
    }

    void *_M_get_deleter(const std::type_info &__ti) const noexcept
    {
        return _M_pi ? _M_pi->_M_get_deleter(__ti) : nullptr;
    }

    bool _M_less(const __shared_count &__rhs) const noexcept
    {
        return std::less<_Sp_counted_base<_Lp> *>()(this->_M_pi, __rhs._M_pi);
    }

    bool _M_less(const __weak_count<_Lp> &__rhs) const noexcept
    {
        return std::less<_Sp_counted_base<_Lp> *>()(this->_M_pi, __rhs._M_pi);
    }

    // Friend function injected into enclosing namespace and found by ADL
    friend inline bool operator==(const __shared_count &__a, const __shared_count &__b) noexcept
    {
        return __a._M_pi == __b._M_pi;
    }

private:
    friend class __weak_count<_Lp>;
    _Sp_counted_base<_Lp> *_M_pi;
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值