shared_ptr的内部实现原理

    本文先分析shared_ptr的内部实现原理,然后实例演示shared_ptr的使用。

1. 实现原理

    shared_ptr的定义如下:

template<class _Ty>
class shared_ptr : public _Ptr_base<_Ty>

    shared_ptr从基类_Ptr_base 继承了如下成员变量(部分源码):

template<class _Ty>
class _Ptr_base
{
private:
    element_type * _Ptr{ nullptr };      //指向资源
    _Ref_count_base * _Rep{ nullptr };   //指向资源引用计数
}

   其中,_Ptr指向资源,_Rep指向资源引用计数。

    _Ref_count_base的定义如下:

class __declspec(novtable) _Ref_count_base
{	// common code for reference counting
private:
	_Atomic_counter_t _Uses;   //记录了引用资源的shared_ptr的个数
	_Atomic_counter_t _Weaks;  //记录了weak_ptr的个数
}

    其中,Uses记录了资源的引用计数,也就是引用资源的shared_ptr 的个数;_Weaks记录了weak_ptr的个数,相当于资源观察者的个数。

    shared_ptr的构造函数定义如下:

template<class _Ux,
    enable_if_t<conjunction_v<conditional_t<is_array_v<_Ty>, _Can_array_delete<_Ux>, _Can_scalar_delete<_Ux>>,
    _SP_convertible<_Ux, _Ty>>, int> = 0>
    explicit shared_ptr(_Ux * _Px)
{	// construct shared_ptr object that owns _Px
    _Setp(_Px, is_array<_Ty>{});
}


template<class _Ux>
void _Setp(_Ux * _Px, false_type)
{	// take ownership of _Px
    _TRY_BEGIN	// allocate control block and set
        _Set_ptr_rep_and_enable_shared(_Px, new _Ref_count<_Ux>(_Px));
    _CATCH_ALL	// allocation failed, delete resource
        delete _Px;
    _RERAISE;
    _CATCH_END
}

    shared_ptr的构造函数中会开辟新的引用计数的资源

    shared_ptr的拷贝构造函数定义如下:

shared_ptr(const shared_ptr& _Other) noexcept
{	// construct shared_ptr object that owns same resource as _Other
    this->_Copy_construct_from(_Other);
}

template<class _Ty2>
void _Copy_construct_from(const shared_ptr<_Ty2>& _Other)
{	// implement shared_ptr's (converting) copy ctor
    if (_Other._Rep)
    {
        _Other._Rep->_Incref();
    }

    _Ptr = _Other._Ptr;
    _Rep = _Other._Rep;
}

    shared_ptr的拷贝构造函数没有开辟新的引用计数的资源,只是引用计数加1。

2.代码实例    

    先看下面出错的例子:

#include <iostream>
#include <memory>
using namespace std;
int main()
{
    // 裸指针指向堆上的对象
    int *p = new int;       
    shared_ptr<int> ptr1(p);
    shared_ptr<int> ptr2(p);
    //两次打印都是1,析构两次,出错
    cout << "use_count = " <<  ptr1.use_count() << endl;
    cout << "use_count = " << ptr2.use_count() << endl;
    getchar();
    return 0;
}

    执行结果:

  

    原因:ptr1(p) 和 ptr2(p)都调用了shared_ptr的构造函数,它们管理同一个资源,但是重新开辟了引用计数的资源。所以引用计数都为1。析构函数会被调用两次,所以程序出错。

    正确的代码如下:

#include <iostream>
#include <memory>
using namespace std;
int main()
{
    // 裸指针指向堆上的对象
    int *p = new int;       
    shared_ptr<int> ptr1(p);
    shared_ptr<int> ptr2(ptr1);
    //两次打印都是2,析构一次,正确
    cout << "use_count = " <<  ptr1.use_count() << endl;
    cout << "use_count = " << ptr2.use_count() << endl;
    getchar();
    return 0;
}

    执行结果:

    原因:ptr1(p) 调用构造函数,ptr2(ptr1)调用拷贝构造函数(没有开辟新的引用计数的资源,只是引用计数加1)。析构函数会被调用一次,所以程序正确。

  • 24
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
shared_ptr是C++11中引入的一种智能指针,可以用于多个指针共享同一个对象,会自动释放内存,是一种安全、高效的内存管理方式。 shared_ptr实现主要包括以下步骤: 1. 定义一个class,命名为shared_ptr,其中定义一个模板T,表示指向的对象类型。 2. 在shared_ptr中定义一个指向T类型对象的指针ptr。 3. 定义一个计数器counter,表示有多少个shared_ptr对象指向同一块内存。 4. 定义一个析构函数,用于释放内存。当counter为0时,释放内存,否则不释放。 5. 定义一个拷贝构造函数,用于实现多个shared_ptr共享同一块内存。当有新shared_ptr指向同一块内存时,counter加1。 6. 定义一个赋值运算符重载函数,用于实现shared_ptr的赋值操作。当有shared_ptr对象被赋值为另一个shared_ptr对象时,counter加1。 7. 定义一个reset函数,用于重置shared_ptr指向的对象。 8. 定义一个get函数,用于获取shared_ptr指向的对象。 9. 定义一个operator->重载函数,用于实现shared_ptr的箭头运算符。当shared_ptr指向的对象是一个类对象时,可以通过箭头运算符来访问类的成员函数和变量。 10. 定义一个operator*重载函数,用于实现shared_ptr的解引用运算符。当shared_ptr指向的对象是一个类对象时,可以通过解引用运算符来访问类的成员函数和变量。 11. 定义一个operator bool重载函数,用于实现shared_ptr的bool类型转换。当shared_ptr指向的对象存在时,返回true,否则返回false。 12. 定义一个make_shared函数,用于创建shared_ptr对象,同时分配内存。 以上就是shared_ptr的主要实现步骤。需要注意的是,在实现shared_ptr时还需要考虑线程安全性和异常安全性等问题,以保证shared_ptr的正确性和可靠性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值