c++ smart_ptr(vs2019 c++ 17) learn 1

#include <memory>
#include <iostream>
#include <cstdio>
#pragma optimize("",off)
char* g_temp_test_valid = nullptr;
std::shared_ptr<char[]> getMem() {
	std::shared_ptr<char[]> pOut(new char[10]);
	strcpy_s(pOut.get(), 10,"hello");
	g_temp_test_valid = pOut.get();
	return pOut;
}
void testSharedPtr()
{
	{
		auto ret = getMem();
		printf("before [%s]\r\n", g_temp_test_valid);
	}
	try
	{
		printf("after [%s]\r\n", g_temp_test_valid);
		printf("exits");
	}
	catch (std::exception & e)
	{
		printf("%s", e.what());
		printf("exception\r\n");
	}

}
int main()
{
	testSharedPtr();
	return 0;
}

ida:

smart_ptr_源码,看接口,有个基类

我们想看其成员的话,里面额外的代码太多了,最方便的是vs2019 自带的watch 本地变量:

吓死个人

不过根据ida 的反汇编,看得出来它就是两个变量,只是由于vs2019 调试能力太强了,导致啥玩意都看出来了,参见如下代码:

其中:

 

// STRUCT TEMPLATE remove_extent
template <class _Ty>
struct remove_extent { // remove array extent
    using type = _Ty;
};

template <class _Ty, size_t _Ix>
struct remove_extent<_Ty[_Ix]> {
    using type = _Ty;
};

template <class _Ty>
struct remove_extent<_Ty[]> {
    using type = _Ty;
};

template <class _Ty>
using remove_extent_t = typename remove_extent<_Ty>::type;

上面模板类的函数,就是为了,当传入的是数组的时候,取元素类型:

参见:https://docs.microsoft.com/en-us/cpp/standard-library/remove-extent-class?f1url=https%3A%2F%2Fmsdn.microsoft.com%2Fquery%2Fdev16.query%3FappId%3DDev16IDEF1%26l%3DEN-US%26k%3Dk(TYPE_TRAITS%2Fstd%3A%3Aremove_extent);k(std%3A%3Aremove_extent);k(remove_extent);k(DevLang-C%2B%2B);k(TargetOS-Windows)%26rd%3Dtrue&view=vs-2019

下面这个引用计数的结构,是智能指针的核心结构了,倒是不着急了解它的细节, 先看看实际代码中,它的初始化是怎么样的


// CLASS _Ref_count_base
class __declspec(novtable) _Ref_count_base { // common code for reference counting
private:
#ifdef _M_CEE_PURE
    // permanent workaround to avoid mentioning _purecall in msvcurt.lib, ptrustu.lib, or other support libs
    virtual void _Destroy() noexcept {
        _STD terminate();
    }

    virtual void _Delete_this() noexcept {
        _STD terminate();
    }
#else // ^^^ _M_CEE_PURE / !_M_CEE_PURE vvv
    virtual void _Destroy() noexcept     = 0; // destroy managed resource
    virtual void _Delete_this() noexcept = 0; // destroy self
#endif // _M_CEE_PURE

    _Atomic_counter_t _Uses  = 1;
    _Atomic_counter_t _Weaks = 1;

protected:
    constexpr _Ref_count_base() noexcept = default; // non-atomic initializations

public:
    _Ref_count_base(const _Ref_count_base&) = delete;
    _Ref_count_base& operator=(const _Ref_count_base&) = delete;

    virtual ~_Ref_count_base() noexcept {} // TRANSITION, should be non-virtual

    bool _Incref_nz() noexcept { // increment use count if not zero, return true if successful
        auto& _Volatile_uses = reinterpret_cast<volatile long&>(_Uses);
        long _Count          = _ISO_VOLATILE_LOAD32(_Volatile_uses);

        while (_Count != 0) {
            const long _Old_value = _INTRIN_RELAXED(_InterlockedCompareExchange)(&_Volatile_uses, _Count + 1, _Count);
            if (_Old_value == _Count) {
                return true;
            }

            _Count = _Old_value;
        }

        return false;
    }

    void _Incref() noexcept { // increment use count
        _MT_INCR(_Uses);
    }

    void _Incwref() noexcept { // increment weak reference count
        _MT_INCR(_Weaks);
    }

    void _Decref() noexcept { // decrement use count
        if (_MT_DECR(_Uses) == 0) {
            _Destroy();
            _Decwref();
        }
    }

    void _Decwref() noexcept { // decrement weak reference count
        if (_MT_DECR(_Weaks) == 0) {
            _Delete_this();
        }
    }

    long _Use_count() const noexcept {
        return static_cast<long>(_Uses);
    }

    virtual void* _Get_deleter(const type_info&) const noexcept {
        return nullptr;
    }
};

 

    explicit shared_ptr(_Ux* _Px) { // construct shared_ptr object that owns _Px
#if _HAS_IF_CONSTEXPR
        if constexpr (is_array_v<_Ty>) {
            _Setpd(_Px, default_delete<_Ux[]>{});
        } else {
            _Temporary_owner<_Ux> _Owner(_Px);
            _Set_ptr_rep_and_enable_shared(_Owner._Ptr, new _Ref_count<_Ux>(_Owner._Ptr));
            _Owner._Ptr = nullptr;
        }


    template <class _UxptrOrNullptr, class _Dx>
    void _Setpd(const _UxptrOrNullptr _Px, _Dx _Dt) { // take ownership of _Px, deleter _Dt
        _Temporary_owner_del<_UxptrOrNullptr, _Dx> _Owner(_Px, _Dt);
        _Set_ptr_rep_and_enable_shared(
            _Owner._Ptr, new _Ref_count_resource<_UxptrOrNullptr, _Dx>(_Owner._Ptr, _STD move(_Dt)));
        _Owner._Call_deleter = false;// 这样写,就不释放了,上面的这些操作如果发生了异常,资源可以正常释放
    }
template <class _UxptrOrNullptr, class _Dx>
struct _Temporary_owner_del {
    _UxptrOrNullptr _Ptr;
    _Dx& _Dt;
    bool _Call_deleter = true;

    explicit _Temporary_owner_del(const _UxptrOrNullptr _Ptr_, _Dx& _Dt_) noexcept : _Ptr(_Ptr_), _Dt(_Dt_) {}
    _Temporary_owner_del(const _Temporary_owner_del&) = delete;
    _Temporary_owner_del& operator=(const _Temporary_owner_del&) = delete;
    ~_Temporary_owner_del() {// 注意,默认,这里是会自动释放所拥有的资源的
        if (_Call_deleter) {
            _Dt(_Ptr);
        }
    }
};

接下来开始看申请ref_count_resource 的操作,以及_set_ptr_rep_and_enable_shared实现:


// CLASS TEMPLATE _Ref_count_resource
template <class _Resource, class _Dx>
class _Ref_count_resource : public _Ref_count_base { // handle reference counting for object with deleter
public:
    _Ref_count_resource(_Resource _Px, _Dx _Dt)
        : _Ref_count_base(), _Mypair(_One_then_variadic_args_t(), _STD move(_Dt), _Px) {}

    virtual void* _Get_deleter(const type_info& _Typeid) const noexcept override {
#if _HAS_STATIC_RTTI
        if (_Typeid == typeid(_Dx)) {
            return const_cast<_Dx*>(_STD addressof(_Mypair._Get_first()));
        }
#else // _HAS_STATIC_RTTI
        (void) _Typeid;
#endif // _HAS_STATIC_RTTI

        return nullptr;
    }

private:
    virtual void _Destroy() noexcept override { // destroy managed resource
        _Mypair._Get_first()(_Mypair._Myval2);
    }

    virtual void _Delete_this() noexcept override { // destroy self
        delete this;
    }

    _Compressed_pair<_Dx, _Resource> _Mypair;
};


压缩匹配数据,继承_Resource 类,存储 _Dx 作为其释放器.
// CLASS TEMPLATE _Ref_count_resource
template <class _Resource, class _Dx>
class _Ref_count_resource : public _Ref_count_base { // handle reference counting for object with deleter
public:
    _Ref_count_resource(_Resource _Px, _Dx _Dt)
        : _Ref_count_base(), _Mypair(_One_then_variadic_args_t(), _STD move(_Dt), _Px) {}

    virtual void* _Get_deleter(const type_info& _Typeid) const noexcept override {
#if _HAS_STATIC_RTTI
        if (_Typeid == typeid(_Dx)) {
            return const_cast<_Dx*>(_STD addressof(_Mypair._Get_first()));
        }
#else // _HAS_STATIC_RTTI
        (void) _Typeid;
#endif // _HAS_STATIC_RTTI

        return nullptr;
    }

private:
    virtual void _Destroy() noexcept override { // destroy managed resource
        _Mypair._Get_first()(_Mypair._Myval2);
    }

    virtual void _Delete_this() noexcept override { // destroy self
        delete this;
    }

    _Compressed_pair<_Dx, _Resource> _Mypair;
};


 

其基类为:


// CLASS _Ref_count_base
class __declspec(novtable) _Ref_count_base { // common code for reference counting
private:
#ifdef _M_CEE_PURE
    // permanent workaround to avoid mentioning _purecall in msvcurt.lib, ptrustu.lib, or other support libs
    virtual void _Destroy() noexcept {
        _STD terminate();
    }

    virtual void _Delete_this() noexcept {
        _STD terminate();
    }
#else // ^^^ _M_CEE_PURE / !_M_CEE_PURE vvv
    virtual void _Destroy() noexcept     = 0; // destroy managed resource 删除管理的资源
    virtual void _Delete_this() noexcept = 0; // destroy self             删除当前这个引用计数块
#endif // _M_CEE_PURE

    _Atomic_counter_t _Uses  = 1;
    _Atomic_counter_t _Weaks = 1;

protected:
    constexpr _Ref_count_base() noexcept = default; // non-atomic initializations

public:
    _Ref_count_base(const _Ref_count_base&) = delete;
    _Ref_count_base& operator=(const _Ref_count_base&) = delete;

    virtual ~_Ref_count_base() noexcept {} // TRANSITION, should be non-virtual

    bool _Incref_nz() noexcept { // increment use count if not zero, return true if successful
        auto& _Volatile_uses = reinterpret_cast<volatile long&>(_Uses);
        long _Count          = _ISO_VOLATILE_LOAD32(_Volatile_uses);

        while (_Count != 0) {
            const long _Old_value = _INTRIN_RELAXED(_InterlockedCompareExchange)(&_Volatile_uses, _Count + 1, _Count);
            if (_Old_value == _Count) {
                return true;
            }

            _Count = _Old_value;
        }

        return false;
    }

    void _Incref() noexcept { // increment use count
        _MT_INCR(_Uses);
    }

    void _Incwref() noexcept { // increment weak reference count
        _MT_INCR(_Weaks);
    }

    void _Decref() noexcept { // decrement use count
        if (_MT_DECR(_Uses) == 0) {// 管理的资源的引用计数为0 的时候,释放该资源
            _Destroy();
            _Decwref();
        }
    }

    void _Decwref() noexcept { // decrement weak reference count
        if (_MT_DECR(_Weaks) == 0) {// 如果有人有这个块的wreak 引用,当弱引用清空到0 的时候,才delete this,也就是清空自身,不然,别人引用自己的时候,会导致非法访问
            _Delete_this();
        }
    }

    long _Use_count() const noexcept {
        return static_cast<long>(_Uses);
    }

    virtual void* _Get_deleter(const type_info&) const noexcept {
        return nullptr;
    }
};

这个就是刚才的,设置smart_ptr的操作

void _Set_ptr_rep_and_enable_shared(_Ux* const _Px, _Ref_count_base* const _Rx) noexcept { // take ownership of _Px
        this->_Ptr = _Px;
        this->_Rep = _Rx;
#if _HAS_IF_CONSTEXPR
        if constexpr (conjunction_v<negation<is_array<_Ty>>, negation<is_volatile<_Ux>>, _Can_enable_shared<_Ux>>) {
            if (_Px && _Px->_Wptr.expired()) {
                _Px->_Wptr = shared_ptr<remove_cv_t<_Ux>>(*this, const_cast<remove_cv_t<_Ux>*>(_Px));
            }
        }
#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv
        _Enable_shared_from_this1(*this, _Px,
            bool_constant<
                conjunction_v<negation<is_array<_Ty>>, negation<is_volatile<_Ux>>, _Can_enable_shared<_Ux>>>{});
#endif // _HAS_IF_CONSTEXPR
    }

这个时候,再次贴上我们从vs 搞来的贴图:

明日再战

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值