自定义实现c++中std::enable_shared_from_this功能

主要概念

std::enable_shared_from_this,能通过其shared_from_this()函数获得当前shared_ptr的副本,指向原指针对象一样,此副本析构的时候不会导致二次析构(如果直接用std::shared_tr<T>(this), 就会有这个问题),因为有了副本,就不会有直接使用原本的shared_ptr对象,而避免shared_ptr的循环引用问题

一般会这样用:

class NodeBase : public std::enable_shared_from_this<NodeBase>
{
public:
    NodeBase()
    {
        std::cout << "NodeBase::constructor()...\n";
    }
    [[nodiscard]] std::shared_ptr<NodeBase> getptr()
    {
        return shared_from_this();
    }
    virtual ~NodeBase()
    {
        std::cout << "NodeBase::destructor()...\n";
    }
};


template<typename T>
class BigUnitFT : public std::enable_shared_from_this<BigUnitFT<T>>
{
public:
    T value;
    BigUnitFT()
    {
        std::cout << "BigUnitFT::constructor()...\n";
    }
    virtual ~BigUnitFT()
    {
        std::cout << "BigUnitFT::destructor()...\n";
    }
};

void testMain()
{
    {
        std::shared_ptr<NodeBase> p0 = std::make_shared<NodeBase>();
        std::shared_ptr<NodeBase> q0 = p0->getptr();
        std::cout << "(p0 == q0): " << (p0.get() == q0.get()) << std::endl;
        std::cout << p0.use_count() << std::endl;
        std::cout << q0.use_count() << std::endl;
    }
    {
        std::shared_ptr<BigUnitFT<double>> p0(new BigUnitFT<double>());
        std::shared_ptr<BigUnitFT<double>> q0 = p0->shared_from_this();
        std::cout << "(p0 == q0): " << (p0.get() == q0.get()) << std::endl;
        std::cout << p0.use_count() << std::endl;
        std::cout << q0.use_count() << std::endl;
    }
}

如果将std::enable_shared_from_this用于更复杂的实现需求中(例如某些类模板、多重继承等应用情况)可能会很不方便,这时候就需要用实现原理自己实现相关功能。先简单看一下源码:

enable_shared_from_this是一个基类,在MSVC中enable_shared_from_this功能实现依赖的两个关键模板函数, 位于:

Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include\memory文件中的template <class _Ty>
class shared_ptr : public _Ptr_base<_Ty> {}

定义中。

Linux GCC 请参见: gcc\libstdc++-v3\include\bits\shared_ptr_base.h

也就是说enable_shared_from_this实际上是基于std::shared_ptr的扩展

// 构造的时候调用
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 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));
        }
    }
}
// 析构的时候调用
void _Set_ptr_rep_and_enable_shared(nullptr_t, _Ref_count_base* const _Rx) noexcept
{ // take ownership of nullptr
    this->_Ptr = nullptr;
    this->_Rep = _Rx;
}

由此可简洁的自定义一个enable_shared_from_this_t类来happy一下,代码如下:

template <class _Ty>
class enable_shared_from_this_t
{
public:
    // 下面这一句是关键代码
    using _Esft_type = enable_shared_from_this_t;
    _NODISCARD std::shared_ptr<_Ty> shared_from_this()
    {
        return std::shared_ptr<_Ty>(_Wptr);
    }
protected:
    constexpr enable_shared_from_this_t() noexcept
    {
    }
    ~enable_shared_from_this_t() = default;

private:
    template <class _Yty>
    friend class std::shared_ptr;
    // _Wptr变量名不可变
    mutable std::weak_ptr<_Ty> _Wptr;
};

自定义实现

如何自定义实现 std::enable_shared_from_this才具有的返回shared_ptr副本功能呢?,直接上代码(MSVC)吧:

class BigUnit
{
public:
    using _Esft_type = BigUnit;
    BigUnit()
    {
        std::cout << "BigUnit::constructor()...\n";
    }
    [[nodiscard]] std::shared_ptr<BigUnit> getSharedPtr()
    {
        return std::shared_ptr<BigUnit>(_Wptr);
    }
    [[nodiscard]] std::shared_ptr<const BigUnit> getSharedPtr() const
    {
        return std::shared_ptr<const BigUnit>(_Wptr);
    }

    virtual ~BigUnit()
    {
        std::cout << "BigUnit::destructor()...\n";
    }

private:
    template <class _Yty>
    friend class std::shared_ptr;

    mutable std::weak_ptr<BigUnit> _Wptr;
};

好了,可以用了。如果还要更高级的功能,自己扩展实现一个shared_ptr<TTTT>。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值