精华内容
下载资源
问答
  • shared_ptr 和weak_ptr

    2021-06-12 12:25:41
    shared_ptr类几乎什么都没有做,它是继承了__shared_ptr, __shared_ptr内部有一个类型为__shared_count类型的成员_M_refcount, __shared_count内部有类型为_Sp_counted_base*的_M_pi的成员, _Sp_counted_base才是...

    shared_ptr

    参考自https://www.jianshu.com/p/b6ac02d406a0

    shared_ptr类几乎什么都没有做,它是继承了__shared_ptr, __shared_ptr内部有一个类型为__shared_count类型的成员_M_refcount, __shared_count内部有类型为_Sp_counted_base*的_M_pi的成员, _Sp_counted_base才是整个shared_ptr功能的核心,通过_Sp_counted_base控制引用计数来管理托管的内存,由图可见_Sp_counted_base内部不持有托管内存的指针,这里__shared_count内部的成员其实是一个继承自_Sp_counted_base的_Sp_counted_ptr类型,_Sp_counted_ptr类型内部持有托管内存的指针_M_ptr, _M_pi是一个_Sp_counted_base基类对象指针,指向_Sp_counted_ptr子类对象内存,这样_M_pi内部就既可以控制引用计数,又可以在最后释放托管内存。

    这里称_M_pi为管理对象,它内部的_M_ptr为托管对象,管理同一块托管对象的多个shared_ptr内部共用一个管理对象(_M_pi), 这里的多个shared_ptr可能是通过第一个shared_ptr拷贝或者移动而来, 管理对象内部有两个成员变量_M_use_count和_M_weak_count, _M_use_count表示托管对象的引用计数,控制托管对象什么时候析构和释放,大概就是有N个shared_ptr的拷贝那引用计数就是N,当引用计数为0时调用托管对象的析构函数且释放内存。_M_weak_count表示管理对象的引用计数,管理对象也是一个内存指针,这块指针是初始化第一个shared_ptr时new出来的,到最后也需要delete,所以使用_M_weak_count来控制管理对象什么时候析构,我们平时用到的weak_ptr内部其实持有的就是这个管理对象的指针,当weak_ptr拷贝时,管理对象的引用计数_M_weak_count就会增加,当_M_weak_count为0时,管理对象_M_pi就会析构且释放内存。

    class shared_ptr

    template <typename _Tp> class shared_ptr : public __shared_ptr<_Tp>
    

    成员函数

    template <typename _Tp1>
    shared_ptr &operator=(const shared_ptr<_Tp1> &__r) noexcept {
      this->__shared_ptr<_Tp>::operator=(__r);
      return *this;
    }
    

    class __shared_ptr

      template <typename _Tp, _Lock_policy _Lp> class __shared_ptr
    

    成员变量

    _Tp *_M_ptr;                     // Contained pointer.
    __shared_count<_Lp> _M_refcount; // Reference counter.
    

    成员函数

       // 重载赋值运算符 
       __shared_ptr &operator=(const __shared_ptr &) noexcept = default;
    
       template <typename _Tp1>
        __shared_ptr &operator=(const __shared_ptr<_Tp1, _Lp> &__r) noexcept {
          _M_ptr = __r._M_ptr;
          _M_refcount = __r._M_refcount; // __shared_count::op= doesn't throw
          return *this;
        }
    
    
      // 构造函数
       template <typename _Tp1>
        explicit __shared_ptr(_Tp1 *__p) : _M_ptr(__p), _M_refcount(__p) {
          __glibcxx_function_requires(
              _ConvertibleConcept<_Tp1 *, _Tp *>) static_assert(sizeof(_Tp1) > 0,
                                                                "incomplete type");
          __enable_shared_from_this_helper(_M_refcount, __p, __p);
        }
    
    	// 析构函数
        ~__shared_ptr() = default;
    
    

    class __shared_count

    成员变量

    _Sp_counted_base<_Lp> *_M_pi;//_M_pi是一个_Sp_counted_base基类对象指针,指向_Sp_counted_ptr子类对象内存,这样_M_pi内部就既可以控制引用计数,又可以在最后释放托管内存。
    

    成员函数

       // 构造函数
      template <typename _Ptr> explicit __shared_count(_Ptr __p) : _M_pi(0) {
          __try {
            _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p); //   _M_pi指向_Sp_counted_ptr子类对象内存
          }
          __catch(...) {
            delete __p;
            __throw_exception_again;
          }
        }
    
      // 析构函数
        ~__shared_count() noexcept {
          if (_M_pi != nullptr)
            _M_pi->_M_release();
        }
     
    
    
       // 重载赋值运算符
       __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;
        }
    
    
        explicit operator bool() const // never throws
        {
          return _M_ptr == 0 ? false : true;
        }
    
    

    class _Sp_counted_base

    template <_Lock_policy _Lp = __default_lock_policy>
    class _Sp_counted_base : public _Mutex_base<_Lp>
    

    成员变量

    private:
      _Atomic_word _M_use_count;  // #shared
      _Atomic_word _M_weak_count; // #weak + (#shared != 0)
    

    成员函数

     _Sp_counted_base() noexcept : _M_use_count(1), _M_weak_count(1) {}
    //注意当shared_ptr拷贝或者移动时_M_weak_count是不会增加的,它表示的是管理对象的计数,只有当__M_use_count为0时_M_weak_count才会减1,除此之外_M_weak_count的数值是由weak_ptr控制的。
    
    virtual ~_Sp_counted_base() noexcept {}
    
    
     void _M_add_ref_copy() {
          __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1);
        }
    
    
     void _M_release() noexcept {
          // Be race-detector-friendly.  For more info see bits/c++config.
          _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_use_count);
          if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1) {
            _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_use_count);
            _M_dispose();
            // There must be a memory barrier between dispose() and destroy()
            // to ensure that the effects of dispose() are observed in the
            // thread that runs destroy().
            // See http://gcc.gnu.org/ml/libstdc++/2005-11/msg00136.html
            if (_Mutex_base<_Lp>::_S_need_barriers) {
              _GLIBCXX_READ_MEM_BARRIER;
              _GLIBCXX_WRITE_MEM_BARRIER;
            }
    
            // Be race-detector-friendly.  For more info see bits/c++config.
            _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
            if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1) {
              _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
              _M_destroy();
            }
          }
        }
    
    
    	void _M_weak_add_ref() noexcept {
          __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1);
        }
    
    
       void _M_weak_release() noexcept {
          // Be race-detector-friendly. For more info see bits/c++config.
          _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
          if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1) {
            _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
            if (_Mutex_base<_Lp>::_S_need_barriers) {
              // See _M_release(),
              // destroy() must observe results of dispose()
              _GLIBCXX_READ_MEM_BARRIER;
              _GLIBCXX_WRITE_MEM_BARRIER;
            }
            _M_destroy();
          }
        }
    
    

    class _Sp_counted_ptr

    template <typename _Ptr, _Lock_policy _Lp>
    class _Sp_counted_ptr final : public _Sp_counted_base<_Lp>
    

    成员变量

    protected:
      _Ptr _M_ptr; // 托管内存的指针
    

    成员函数

    explicit _Sp_counted_ptr(_Ptr __p) : _M_ptr(__p) {}
    
    
     virtual void _M_dispose() noexcept { delete _M_ptr; }
    
     virtual void _M_destroy() noexcept { delete this; }
    

    weak_ptr

    参考自https://www.jianshu.com/p/b6ac02d406a0

    注意当shared_ptr拷贝或者移动时_M_weak_count是不会增加的,它表示的是管理对象的计数,只有当__M_use_count为0时_M_weak_count才会减1,除此之外_M_weak_count的数值是由weak_ptr控制的。

    weak_ptr内部其实和shared_ptr内部持有的是同一个管理对象指针,即_Sp_counted_base的指针,当weak_ptr赋值、拷贝、析构时候,_Sp_counted_base内部的_M_weak_count会相应加减。当_M_weak_count为0时,表示不再需要管理对象来控制托管对象,调用_M_destroy()的delete this来释放管理对象内存。

    weak_ptr不会延长原生指针所指向的对象的生命周期,实际上weak_ptr也没有原生指针的构造函数,只能由shared_ptr或weak_ptr进行构造。是一种不已延长生命周期为目的的只能指针。

    class weak_ptr

    template <typename _Tp> class weak_ptr : public __weak_ptr<_Tp>
    

    成员函数

    template <typename _Tp1>
    weak_ptr &operator=(const weak_ptr<_Tp1> &__r) noexcept {
      this->__weak_ptr<_Tp>::operator=(__r);
      return *this;
    }
    
     template <typename _Tp1,
                  typename = typename std::enable_if<
                      std::is_convertible<_Tp1 *, _Tp *>::value>::type>
        weak_ptr(const weak_ptr<_Tp1> &__r) noexcept : __weak_ptr<_Tp>(__r) {}
    
    
    // 用来延长生命周期
        shared_ptr<_Tp> lock() const noexcept {
    #ifdef __GTHREADS
          if (this->expired())
            return shared_ptr<_Tp>();
    
          __try {
            return shared_ptr<_Tp>(*this);
          }
          __catch(const bad_weak_ptr &) { return shared_ptr<_Tp>(); }
    #else
          return this->expired() ? shared_ptr<_Tp>() : shared_ptr<_Tp>(*this);
    #endif
        } 
    
    

    class __weak_ptr

    template <typename _Tp, _Lock_policy _Lp> class __weak_ptr
    

    成员变量

    _Tp *_M_ptr;                   // Contained pointer.
    __weak_count<_Lp> _M_refcount; // Reference counter.
    

    成员函数

      template <typename _Tp1,
                  typename = typename std::enable_if<
                      std::is_convertible<_Tp1 *, _Tp *>::value>::type>
        __weak_ptr(const __shared_ptr<_Tp1, _Lp> &__r) noexcept
            : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) {}
    
    
    template <typename _Tp1>
    __weak_ptr &operator=(const __weak_ptr<_Tp1, _Lp> &__r) noexcept {
      _M_ptr = __r.lock().get();
      _M_refcount = __r._M_refcount;
      return *this;
    }
    
    __weak_ptr(const __weak_ptr &) noexcept = default;
    
     ~__weak_ptr() = default;
    
    bool expired() const noexcept {
      return _M_refcount._M_get_use_count() == 0;
    }
    

    class __weak_count

    template <_Lock_policy _Lp> class __weak_count
    

    成员变量

    _Sp_counted_base<_Lp> *_M_pi;
    

    成员函数

    __weak_count(const __weak_count<_Lp> &__r) noexcept : _M_pi(__r._M_pi) {
      if (_M_pi != 0)
        _M_pi->_M_weak_add_ref();
    }
    
    __weak_count<_Lp> &operator=(const __weak_count<_Lp> &__r) noexcept {
          _Sp_counted_base<_Lp> *__tmp = __r._M_pi;
          if (__tmp != 0)
            __tmp->_M_weak_add_ref();
          if (_M_pi != 0)
            _M_pi->_M_weak_release();
          _M_pi = __tmp;
          return *this;
     }
    
     ~__weak_count() noexcept {
          if (_M_pi != 0)
            _M_pi->_M_weak_release();
     }
    
    展开全文
  • shared_ptr和weak_ptr

    2020-11-18 15:42:10
    程序中需要管理各种各样的资源,为了避免内存泄露,必须确保在资源再也不需要时释放资源,智能指针提供了这一功能。C++标准提供了两大类智能指针,这里主要介绍shared_ptr。多个shared_ptr可以共享...2、weak_ptr ...

    程序中需要管理各种各样的资源,为了避免内存泄露,必须确保在资源再也不需要时释放资源,智能指针提供了这一功能。C++标准提供了两大类智能指针,这里主要介绍shared_ptr。多个shared_ptr可以共享同一个资源,通过引用计数来计算资源被引用次数,并在最后一个拥有资源的shared_ptr被销毁时释放资源。

    1、shared_ptr

    shared_ptr定义在中,支持下列操作:

    函数作用
    shared_ptr sp默认构造函数
    shared_ptr sp(ptr)构造函数
    shared_ptr sp(ptr, del)构造函数,指定其资源和deleter
    shared_ptr sp(ptr, del, ac)构造函数,指定资源、deleter和allocator
    shared_ptr sp(sp2)复制构造函数,sp和sp2共享资源
    shared_ptr sp(move(sp2))移动语义构造函数
    shared_ptr sp(sp2, ptr)alias构造函数,和sp2共享拥有权,但指向*ptr
    shared_ptr sp(wp)wp是weak_pointer
    shared_ptr sp(move(up))up是unique_ptr
    shared_ptr sp(move(ap))ap是auto_ptr
    sp.~shared_ptr()析构函数,调用deleter
    sp = sp2赋值操作,sp共享sp2的资源
    sp = move(sp2)移动语义赋值操作,sp2把拥有权交给sp
    sp = move(up)up是unique_ptr
    sp = move(ap)ap是auto_ptr
    sp1.swap(sp2)交换sp1和sp2的pointer和deleter
    swap(sp1,sp2)交换sp1和sp2的pointer和deleter
    sp.reset()重置shared_ptr为空
    sp.reset(ptr)重置shared_ptr,指定资源,使用默认deleter
    sp_reset(ptr, del)重置shared_ptr,指定资源和deleter
    sp_reset(ptr, del, ac)重置shared_ptr,指定资源、deleter和allocator
    make_shared()为资源构建一个shared_ptr
    sp.get()返回指向资源的指针
    *sp返回资源
    sp->…访问资源对象的成员
    sp.use_count()返回资源的引用计数
    sp.unique()判断资源是否只被引用一次
    ==、!=、<、>、<=、>=判断指向资源的pointer

    基本用法

    shared_ptr<string> sp_book(new string("C++"));
    shared_ptr<string> sp_song = new string("i want something just like this");			//error
    
    sp_book->append(" Standard");
    cout << *sp_book << endl;
    

    定义一个管理字符串的智能指针sp_book后,就可以像普通指针一样使用sp_book,上述代码分别使用 -> 操作符访问 string 成员函数 append ,和使用 * 操作符获取字符串对象。但是注意,接受单一指针作传参的构造函数被声明为explicit,所以shared_ptr不支持指针到shared_ptr的隐式类型转换,所以对 sp_song 的赋值会提示编译错误。

    make_shared

    make_shared可以用来创建一个shared_ptr对象,但比构造函数更高效。因为构造函数需要申请两次内存,而make_shared只需要一次。
    shared_ptr内部数据可以分为两部分:数据块和控制块。数据块就是指向资源的指针,控制块包括引用计数等数据。
    shared_ptr的构造函数传参一般是动态申请内存、指向资源对象的指针,这是第一次内存分配,对应shared_ptr的数据块;构造函数内存再为其控制块申请内存,这是第二次内存分配。
    make_shared是一个不定参函数模板,根据传参匹配资源对象类的构造函数(所以,make_shared的对象必须有公开的构造函数)。所以,使用make_shared不用先在外部为数据块申请内存,可以在其内部为数据块和控制块同时申请内存。

    class File
    {
    public:
    	File(string filename)
    	{
    		std::cout << "File(string)" << std::endl;
    	}
    
    	File()
    	{
    		std::cout << "File()" << std::endl;
    	}
    };
    
    shared_ptr<File> sp1 = make_shared<File>();				// 输出File()
    shared_ptr<File> sp2 = make_shared<File>("main.cpp");	// 输出file(string)
    

    使用shared_ptr共享数据

    string *str = new string("C++");
    shared_ptr<string> sp1(str);
    
    shared_ptr<string> sp2 = sp1;		// ok
    shared_ptr<string> sp3(sp1);		// ok
    shared_ptr<string> sp4(str);		// error
    

    智能指针之间共享资源时应该使用复制构造函数或者赋值操作符,它们之间共享控制块数据,也就是共享一个引用计数器;sp4的操作会产生两个引用计数器,造成资源释放两次。

    enable_shared_from_this

    前面提到,共享数据的智能指针是应该通过复制构造函数或赋值操作符产生的。所以,如果在被shared_ptr管理的类内部需要用到shared_ptr对象,不能直接用this指针构造一个shared_ptr,否则会导致重复释放资源对象。
    正确做法是继承enable_shared_from_this类模板,调用成员函数shared_from_this。如果当前对象被shared_ptr引用,shared_from_this函数会构建一个shared_ptr对象并返回,引用计数加1;否则会抛出bad_weak_ptr异常。

    class Z : public std::enable_shared_from_this<Z>
    {
    public:
    	void output()
    	{
    		shared_ptr<Z> sp = shared_from_this();
    		std::cout << sp.use_count() << endl;
    	}
    
    	~Z()
    	{
    		std::cout << "~Z()" << std::endl;
    	}
    };
    
    shared_ptr<Z> sp(new Z);
    sp->output();
    

    自定义deleter

    shared_str的默认deleter会对资源指针执行delete操作来释放资源,但是对于一些特殊的资源(比如数组需要执行delete []操作,文件需要执行close操作等),默认deleter并不适用,所以需要自行定义deleter。一些构造函数和reset成员函数可以指定deleter,deleter传参可以是函数、函数对象或者lamba表达式。

    void arrayDelete(int *p)
    {
    	cout << "arrayDelete" << endl;
    	delete[] p;
    }
    
    class arrayDeleter
    {
    public:
    	void operator () (int *p)
    	{
    		cout << "arrayDeleter" << endl;
    		delete[] p;
    	}
    };
    
    // 传函数
    shared_ptr<int> sp(new int[10], arrayDelete);
    
    // 传lambda表达式
    shared_ptr<int> sp(new int[10], [](int *p) {
    	delete[] p;
    	cout << "arrayDeleter" << endl;
    });
    
    // 传函数对象
    shared_ptr<int> sp(new int[10], arrayDeleter());
    

    alias构造

    shared_ptr有一个特殊的构造函数 shared_ptr sp(sp2, ptr),称作alias构造函数,其语义是共享控制块不共享数据块,在 sp 和 sp2 的生命周期都结束时,sp2 引用的资源对象会被释放,ptr 指向的资源不会被释放。

    2、weak_ptr

    weak_ptr是一种共享资源、但不拥有资源的智能指针, 所以weak_ptr不会引起资源引用计数的增减。

    weak_ptr支持下列操作:

    函数作用
    weak_ptr wp默认构造函数
    weak_ptr wp(sp)基于shared_ptr构造weak_ptr对象,和shared_ptr共享资源
    weak_ptr wp(wp2)复制构造函数,和另一个weak_ptr共享资源
    wp = wp2赋值操作符, 和另一个weak_ptr共享资源
    wp = sp用shared_ptr对weak_ptr对象赋值,和shared_ptr共享资源
    wp.swap(wp2)交换两个weak_ptr的资源指针
    swap(wp1, wp2)交换两个weak_ptr的资源指针
    wp.reset()重置weak_ptr为空
    wp.use_count()返回weak_ptr拥有的资源,被shared_ptr引用的次数
    wp.expired()判断weak_ptr拥有的资源,被shared_ptr引用次数是否为0
    wp.lock()返回一个和weak_ptr共享资源的shared_ptr,会引起引用计数加1

    使用weak_ptr解决shared_ptr引用成环的问题

    class Node
    {
    public:
    	shared_ptr<Node> sp_parent;
    	shared_ptr<Node> sp_child;
    
    	void setparent(shared_ptr<Node> p)
    	{
    		sp_parent = p;
    	}
    
    	void setchild(shared_ptr<Node> c)
    	{
    		sp_child = c;
    	}
    
    	~Node()
    	{
    		cout << "~Node()" << endl;
    	}
    };
    
    int main()
    {
    	{
    		shared_ptr<Node> parent(new Node());				// sp1
    		shared_ptr<Node> child(new Node());					// sp2
    		parent->setchild(child);
    		child->setparent(parent);
    	}
    }
    

    代码中各个对象的关系如下图所示,parent和child是堆上两个node对象,分别用shared_ptr sp1和sp2管理,其内部也通过sp_child和sp_parent相互引用,这种成环引用的结果是parent和child的引用计数永远不会变成0,也就不会被delete。

    parent
    child
    sp_child
    sp_parent
    sp1
    sp2

    我们需要把sp_child和sp_parent中的至少一个改用weak_ptr来破坏成环引用。假如sp_child改用weak_ptr wp_child,那么child只被sp2拥有:
    1、当sp1、sp2被销毁时,parent引用计数变为1,child的引用计数变为0;
    2、child被delete,所以sp_parent被销毁,parent引用计数变为0;
    3、parent被delete。

    weak_ptr的使用

    weak_ptr共享shared_ptr的资源,但不拥有资源,所以使用前必须确认资源是否存在:
    1、使用lock()
    2、使用expired(),比use_count()效率更高
    3、利用构造函数从weak_ptr对象构造一个shared_ptr对象,如果资源不存在,构造函数会抛出bad_weak_ptr异常

    展开全文
  • 浅析shared_ptr和weak_ptr

    2020-07-22 00:24:55
    2. weak_ptr不控制对象的生命周期,它是弱引用。如果对象还活着,它可以提升为有效的shared_ptr,如果对象已经死了, 则提升失败,返回一个空的shared_ptr,提升行为是安全的(lock)。—————个人理解:wea

    1. shared_ptr控制对象的生命周期。shared_ptr是强引用,只要有一个指向x对象的shared_ptr存在,则x对象就不会析构。

    当指向对象x的最后一个shared_ptr析构或reset时,x保证会被销毁。——————着重理解智能指针“引用计数”的概念

    2. weak_ptr不控制对象的生命周期,它是弱引用。如果对象还活着,它可以提升为有效的shared_ptr,如果对象已经死了,

    则提升失败,返回一个空的shared_ptr,提升行为是安全的(lock)。—————个人理解:weak_ptr可以看作是shared_ptr的

    助手,它通过成员函数lock()从管理的shared_ptr获取一个可用的shared_ptr对象,用来管理资源。当其成员函数expired==true

    是,lock()返回一个存储空指针的shared_ptr;

    3. shared_ptr和weak_ptr的"计数"在主流平台上是原子操作,没有用锁。

    4. shared_ptr和weak_ptr的线程安全级别与std::string和STL容器是一样的。

    展开全文
  • 智能指针---shared_ptr和weak_ptr

    千次阅读 2016-06-20 11:46:13
    下面介绍一下boost库中的shared_ptr和weak_ptr:Shared_ptr:当进行拷贝赋值操作时, shared_ptr所指向的对象的引用计数都会增加,一旦变为0,就会自动释放自己管理的对象。(shared_ptr所指向的对象有一个被释放时...

    智能指针主要解决被多个对象引用时,资源如何释放的问题。

    下面介绍一下boost库中的shared_ptr和weak_ptr:

    Shared_ptr:当进行拷贝和赋值操作时, shared_ptr所指向的对象的引用计数都会增加,一旦变为0,就会自动释放自己管理的对象。(shared_ptr所指向的对象有一个被释放时,引用计数就会减1)

    Weak_ptr: weak_ptr是一种不控制所指向对象生存周期的智能指针,它指向一个shared_ptr管理的对象时,并不会改变对象的引用计数(引用计数不增加),一旦最后一个指向shared_ptr的对象被销毁,对象就会被释放,即使有weak_ptr指向该对象,还是会被释放。

    当创建一个weak_ptr时,要用一个shared_ptr来初始化,由于对象可能不存在,我们不能使用weak_ptr来访问对象,通过调用lock()方法,检查对象是否存在,若存在,则返回一个指向共享对象的shared_ptr.

    原理:在创建共享对象时,要使用强指针 shared_ptr,若将该对象给其他线程时,则需要将强指针 shared_ptr转化为弱指针weak_ptr
    (强指针的引用计数会增加,不转化为弱指针则一旦被其他线程调用,则该对象将一直不能析构,weak_ptr对象引用资源不会增加引用计数)要是弱指针weak_ptr想访问该对象时,不能通过weak_ptr来直接访问资源,需要进行提升(shared_ptr能保证自己没被释放之前,所管理的资源是不会被释放的,当shared_ptr引用计数为0时,释放资源,即使有weak_ptr指向它,而weak_ptr通过lock()方法来判断所管理的资源是否被释放,访问时要进行提升)weak_ptr为shared_ptr,将该弱指针提升为强指针,若提升成功,指针不为空,否则为空。

    这里写图片描述

    重磅推荐《linux多线程服务器编程》—第一章1.6节 神器shared_ptr/weak_ptr 书目作者陈硕(很腻害的一个大神)

    附上一个自己实现的智能指针,通过链表来存储这些被引用的资源,当我们在实现指针的拷贝,赋值,析构等操作时,资源引用计数会相应的增加和减少。会遍历链表找到该资源的类型,对该资源计数引用增加减少,若计数减少为0时,则释放该资源节点。

    //智能指针
    class HeapTable//给资源上的指针计数
    {
    public:
         static HeapTable *Getinstance()//单例  不同类型实例化只能在同一个链表
         {
                 static HeapTable  mHeapTable;
                 return &mHeapTable;
         }
         ~HeapTable()
         {
             Node *pcur=phead;
             while (pcur != NULL)
             {
                 phead=phead->mpnext;
                 delete pcur;
                 pcur=phead;
             }
         }
        void addRef(void *ptr)
        {
            Node *pcur=phead->mpnext;
            while (pcur != NULL)
            {
                if (pcur->paddr == ptr)//查找到对该资源计数器加1
                {
                    pcur->mcount++;
                    return;
                }
                pcur=pcur->mpnext;
            }
            pcur=new Node;//没查找到 进行头插
            pcur->mpnext=phead->mpnext;
            phead->mpnext=pcur;
    
        }
        void delRef(void *ptr)
        {
            Node *pcur=phead->mpnext;
            while (pcur != NULL)
            {
                if (pcur->paddr == ptr)//查找到对该资源计数器减1
                {
                    pcur->mcount--;
                    return;
                }
                pcur=pcur->mpnext;
            }
        }
        int GetRef(void *ptr)
        {
            Node *pcur=phead->mpnext;
            while (pcur != NULL)
            {
                if (pcur->paddr == ptr)
                {
                    return pcur->mcount;
                }
                pcur=pcur->mpnext;
            }
            return -1;
        }
    
    private:
        HeapTable(){phead = new Node;}
        class Node
        {
        public:Node(void *ptr=NULL):mcount(0),paddr(ptr),mpnext(NULL)
               {
                   if (paddr != NULL)
                   {
                       mcount=1;
                   }
               }
            int mcount;
            void *paddr;//指向资源
            Node *mpnext;
        };
        Node *phead;
    };
    
    template<typename T>
    class CsmartPtr
    {
    public:
        CsmartPtr(T* str = NULL):mpstr(str)//构造
        {
            if (mpstr != NULL)
            {
                addRef();
            }
        }
    
        CsmartPtr(const CsmartPtr<T> &src):mpstr(src.mpstr)//拷贝构造
        {
            if (mpstr != NULL)
            {
                addRef();
            }
        }
    
        CsmartPtr<T>& operator=(const CsmartPtr<T> &src)//赋值运算符重载
        {
            if (this == &src)//防止自赋值
            {
                return *this;
            }
            if (mpstr != NULL)//释放原来的空间
            {
                delRef();
                if (GetRef() == 0)
                {
                    delete mpstr;
                    mpstr=NULL;
                }   
            }
    
            mpstr=src.mpstr;
             addRef();
            return *this;
        }
    
        ~CsmartPtr()
        {
            cout<<"this"<<this<<endl;
            delRef();
            if (GetRef() == 0)
            {
                delete mpstr;
                mpstr=NULL;
            }
        }
    
        T & operator *(){return *mpstr;}
        const T & operator *()const{return *mpstr;}
    
        T* operator ->(){return mpstr;}
        const T * operator ->()const{return mpstr;}
    
        void addRef(){ mpHeapTab->addRef(mpstr);}
        void delRef(){ mpHeapTab->delRef(mpstr);}
        int GetRef() {return mpHeapTab->GetRef(mpstr);}
    
    
    private:
        T *mpstr;
        static HeapTable *mpHeapTab;//静态指针
    };
    
    //静态变量在全局进行初始化
    template<typename T>
    HeapTable*CsmartPtr<T>::mpHeapTab=HeapTable::Getinstance();
    
    int main()
    {
        int *p = new int;
    
        CsmartPtr<int>pointer1(new int);
        CsmartPtr<int>pointer2(new int);
        CsmartPtr<int>pointer3(pointer1);
        pointer2=pointer1;
    
        CsmartPtr<char> pointer4((char*)p);
    
        return 0;
    }
    

    这里写图片描述

    展开全文
  • shared_ptr shared_ptr是用来智能管理内存的,shared_ptr的 构造函数,拷贝构造,拷贝赋值 这三个动作都会导致 引用计数的增加,析构函数,移动拷贝,移动赋值 这三个动作都会导致 引用计数...weak_ptr shared_ptr
  • 文章目录1 shared_ptr使用介绍1.1 shared_ptr使用介绍1.2 shared_ptr的使用陷阱 1 shared_ptr使用介绍 1.1 shared_ptr使用介绍 熟悉了unique_ptr 后,其实我们发现unique_ptr 这种排他型的内存管理并不能适应所有...
  • c++ 智能指针- shared_ptr和weak_ptr

    千次阅读 2014-10-27 18:10:09
    c++中的智能指针有很多种,其中以shared_ptr和weak_ptr最为重要(个人观点),掌握了这两个智能指针的原理,其它的就很好理解了。 shared_ptr是典型的引用计数型智能指针,相信很多c++程序员都写过功能类似的智能...
  • weak_ptr也是一个引用计数型的智能指针,但是它不增加对象的引用计数,即弱(weak)引用。 Shared_ptr在下列情况之一出现时销毁对象并释放内存: 最后占有std::shared_ptr对象被销毁时; 最后占有std::shared_ptr...
  • STL一共给我们提供了四种智能指针:auto_ptr、unique_ptrshared_ptr和weak_ptr 所有的智能指针类都有一个explicit构造函数,以指针作为参数。比如auto_ptr的类模板原型为: templetclass T> class a
  • C++11 shared_ptr和weak_ptr

    2020-09-03 01:37:00
    #include<iostream> using namespace std; //share_ptr是带了引用... std::shared_ptr<int> sptr(p); std::shared_ptr<int> sptr2(new int(4)); std::shared_ptr<int> sptr3 = sptr2; ...
  • shared_ptr shared_ptr 是一个标准的共享所有权的智能指针,允许多个指针指向同一个对象,定义在 memory 文件中,命名空间为 std。shared_ptr最初实现于Boost库中,后由 C++11 引入到 C++ STL。shared_ptr 利用引用...
  • boost智能指针之shared_ptr和weak_ptr

    千次阅读 2015-01-29 09:09:07
    std::auto_ptr很多的时候并不能满足我们的要求,比如auto_ptr不能用作STL容器的元素。boost的smart_ptr中提供了4种智能指针2种智能指针数组来作为std::auto_ptr的补充。...weak_ptrweak_ptrshared_ptr 的观察员
  • 结合shared_ptrweak_ptr 一个实例。 感觉这个例子很好, 结合了很多知识技术。这个实例功能是非常简单模拟实现std::vector。 (只是非常简单一些操作),当然也可以继续扩展,甚至扩展为模板,主要是用于学习。主要...
  • 浅析shared_ptr 和weak_ptr、定制删除器

    千次阅读 2017-04-17 17:16:20
    记录了有多少个shared_ptrs共同指向一个对象(即引用计数),它基本上解决了在使用c++开发过程中不可避免的使用指针而遇到的许多问题,例如:内存泄漏内存的提前释放,还有由于指针内存申请而产生的异常问题等。...
  • shared_ptr 共享指针的最显著特点就是计数器。 shared_ptr<string> p0; cout << p0.use_count() << endl; shared_ptr<string> p1(new string("hello")); cout << p1.use_count() ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 11,824
精华内容 4,729
关键字:

shared_ptr和weak_ptr