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

#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;
}

有两个申请操作,一个存储 new char[10],一个存储引用计数、new char[10]、deleter

这就是https://herbsutter.com/2013/05/29/gotw-89-solution-smart-pointers/ 所说的overhead。

为了验证文中观点,我们看下std::make_share 的内存结构

参见:https://www.cnblogs.com/apocelipes/p/10346928.html,由于c++ 17 不支持std::make_share<char[]>(10);这样的语法,我们用一个自定义的数据类型好了:

#include <memory>
#include <iostream>
#include <cstdio>
#pragma optimize("",off)
template<size_t t>
struct DATA
{
	char data[t];
};
char* g_temp_test_valid = nullptr;
std::shared_ptr<DATA<40>> getMemByMakeShare()
{
	auto pOut = std::make_shared<DATA<40>>();

	g_temp_test_valid = pOut.get()->data;
	strcpy_s(pOut.get()->data, "hello");
	return pOut;
}
void testSharedPtr()
{
	{
		auto ret = getMemByMakeShare();
		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;
}

实现为:

// FUNCTION TEMPLATE make_shared
template <class _Ty, class... _Types>
_NODISCARD shared_ptr<_Ty> make_shared(_Types&&... _Args) { // make a shared_ptr
    const auto _Rx = new _Ref_count_obj2<_Ty>(_STD forward<_Types>(_Args)...);
    shared_ptr<_Ty> _Ret;
    _Ret._Set_ptr_rep_and_enable_shared(_STD addressof(_Rx->_Storage._Value), _Rx);
    return _Ret;
}

 


// CLASS TEMPLATE _Ref_count_obj2
template <class _Ty>
class _Ref_count_obj2 : public _Ref_count_base { // handle reference counting for object in control block, no allocator
public:
    template <class... _Types>
    explicit _Ref_count_obj2(_Types&&... _Args) : _Ref_count_base() {
        _Construct_in_place(_Storage._Value, _STD forward<_Types>(_Args)...);
    }

    ~_Ref_count_obj2() {
        // nothing to do, _Storage._Value was already destroyed in _Destroy
    }

    union {
        _Wrap<_Ty> _Storage;//这里显然,是包含了类的内存,注意本类的声明是继承了Ref_count_base,因此,内存结构是铁板一块
    };

private:
    virtual void _Destroy() noexcept override { // destroy managed resource
        _Destroy_in_place(_Storage._Value);// 调用析构函数
    }

    virtual void _Delete_this() noexcept override { // destroy self
        delete this;// 真正释放内存
    }
};

基类还是我们熟悉的,引用计数的基类


// 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;
    }
};
    template <class _Ux>
    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
    }

这样就很清晰的对应了std::make_shared 对应的语义,只申请整块内存,同时存放引用计数和对象,不可定义deleter(因为这里用的是placed new 和 placed delete。

 

对于小块类来说挺好,对大块的内存,会导致大块内存不被释放。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值