C++ make_shared

        在使用std::shared_ptr时,有两种不同的构造方式,如:

#include <iostream>
#include <memory>

int main(){

  std::shared_ptr<int> sp1(new int(10));
  std::shared_ptr<int> sp2 = std::make_shared<int>(10);
  return 0;
}

        C++11 中引入了智能指针, 同时还有一个模板函数 std::make_shared 可以返回一个指定类型的 std::shared_ptr, 那与 std::shared_ptr 的构造函数相比它能给我们带来什么好处呢

make_shared初始化的优点

1、提高性能

shared_ptr 需要维护引用计数的信息:
强引用, 用来记录当前有多少个存活的 shared_ptrs 正持有该对象. 共享的对象会在最后一个强引用离开的时候销毁( 也可能释放).
弱引用, 用来记录当前有多少个正在观察该对象的 weak_ptrs. 当最后一个弱引用离开的时候, 共享的内部信息控制块会被销毁和释放 (共享的对象也会被释放, 如果还没有释放的话).
        如果你通过使用原始的 new 表达式分配对象, 然后传递给 shared_ptr (也就是使用 shared_ptr 的构造函数) 的话, shared_ptr 的实现没有办法选择, 而只能单独的分配控制块:需要开辟两块内存空间,一块内存空间 ptr 指向存储的数据;另外一块内存空间 ref 指向引用计数:强引用和弱引用;

 源码:

	// CLASS TEMPLATE shared_ptr
template<class _Ty>
	class shared_ptr
		: public _Ptr_base<_Ty>
	{	// class for reference counted resource management
private:
	using _Mybase = _Ptr_base<_Ty>;
......

//share_ptr 继承于_Ptr_base  
	// CLASS TEMPLATE _Ptr_base
template<class _Ty>
	class _Ptr_base
	{	// base class for shared_ptr and weak_ptr
public:
......
private:
	element_type * _Ptr{nullptr};
	_Ref_count_base * _Rep{nullptr};
......
}

可以看出:在share_ptr 继承于  _Ptr_base,_Ptr_base中有两个指针:

    element_type * _Ptr{nullptr};  指向管理的数据
    _Ref_count_base * _Rep{nullptr};指向引用计数

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

	virtual void _Delete_this() noexcept
		{	// permanent workaround to avoid mentioning _purecall in msvcurt.lib, ptrustu.lib, or other support libs
		_STD terminate();
		}
#else /* ^^^ _M_CEE_PURE ^^^ // vvv !_M_CEE_PURE vvv */
	virtual void _Destroy() noexcept = 0;
	virtual void _Delete_this() noexcept = 0;
#endif /* _M_CEE_PURE */

	_Atomic_counter_t _Uses;//强引用计数
	_Atomic_counter_t _Weaks;//弱引用计数

protected:
	_Ref_count_base()
		: _Uses(1), _Weaks(1)	// non-atomic initializations
		{	// construct
		}

如果使用std::make_shared来替换:

        一次分配就足够了,内存分配效率高。这是因为std::make_shared申请一个单独的内存块来同时存放int对象和控制块。这个优化减少了程序的静态大小,因为代码只包含一次内存分配的调用,并且这会加快代码的执行速度,因为内存只分配了一次。另外,使用std::make_shared消除了一些控制块需要记录的信息,这样潜在地减少了程序的总内存占用。

         同时使用make_shared可以降低内存泄漏的风险。如果不使用make_shared ,当 new int 时候成功,但是 new _Ref_count_base  失败时,share_ptr在构造时失败,无法调用析构函数,导致new int 的内存无法释放;

缺点

1 make_shared 无法自定义删除器

2 对象的内存可能无法及时回收

make_shared 只分配一次内存, 这看起来很好. 减少了内存分配的开销. 问题来了, weak_ptr 会保持控制块(强引用, 以及弱引用的信息)的生命周期, 而因此连带着保持了对象分配的内存, 只有最后一个 weak_ptr 离开作用域时, 内存才会被释放. 原本强引用减为 0 时就可以释放的内存, 现在变为了强引用, 若引用都减为 0 时才能释放, 意外的延迟了内存释放的时间. 这对于内存要求高的场景来说, 是一个需要注意的问题.

shared_ptr 和weak_ptr的实现

关于share_ptr 和weak_ptr的使用C++ 智能指针_LIJIWEI0611的博客-CSDN博客

在其中的引用计数部分,增加弱引用指针:

当强智能指针shared_ptr的引用计数为0时,析构资源
当弱智能指针weak_ptr的引用计数为0时,析构引用计数对象

#include<iostream>
#include<new>
#include<stdio.h>
#include<atomic> 
using namespace std;

//仿写C++的shared_ptr和weak_ptr

//当强智能指针shared_ptr的引用计数为0时,析构资源
//当弱智能指针weak_ptr的引用计数为0时,析构引用计数对象

class Object//实例类
{
private:
  int value;
public:
  Object(int x = 0) :value(x) { cout << "construct object" << endl; }
  ~Object() { cout << "deconstruct object" << endl; }
  int& Value() { return value; }
  const int& Value() const { return value; }
};


  template<class T>
  class RefCnt//引用计数类
  {
  private:
    T* mPtr;
    std::atomic<int> mCnt_s;	   // shared_ptr;
    std::atomic<int> mCnt_w;       // weak_ptr
  public:
    RefCnt(T* p = nullptr) : mPtr(p)
    {
      if (mPtr != nullptr)
      {
        mCnt_s = 1;
        mCnt_w = 0;
      }
    }
    void addRef_s() { mCnt_s++; }//强智能指针引用计数
    int delRef_s() { return --mCnt_s; }
    int getCnt_s() const { return mCnt_s.load(); }

    void addRef_w() { mCnt_w++; }//弱智能指针引用计数
    int delRef_w() { return --mCnt_w; }
    int getCnt_w() const { return mCnt_w; }

  };

  template<typename T>
  struct MyDeletor//删除器类
  {
    void operator()(T* ptr) const
    {
      delete ptr;
    }
  };

  template<class T>
  class weak_ptr;//弱智能指针类型声明

  template<typename T, typename Deletor = MyDeletor<T> >
  class shared_ptr//强智能指针类型
  {
  public:
    shared_ptr(T* ptr = nullptr) :mPtr(ptr), mpRefCnt(nullptr)//构造函数
    {
      if (mPtr != nullptr)
      {
        mpRefCnt = new RefCnt<T>(ptr);
      }
    }
    ~shared_ptr()//析构函数
    {
      if (mPtr != nullptr && 0 == mpRefCnt->delRef_s())
      {
        mDeletor(mPtr);
        if (0 == mpRefCnt->getCnt_w())
        {
          delete mpRefCnt;
        }
      }
      mPtr = nullptr;
      mpRefCnt = nullptr;
    }
    T& operator*() const { return *mPtr; }
    T* operator->() const { return mPtr; }

    shared_ptr(const shared_ptr<T>& src)//拷贝构造函数
      :mPtr(src.mPtr), mpRefCnt(src.mpRefCnt)
    {
      if (mPtr != nullptr)
      {
        mpRefCnt->addRef_s();
      }
    }
    shared_ptr<T>& operator=(const shared_ptr<T>& src)//赋值重载函数
    {
      if (this == &src || this->mPtr == src.mPtr) return *this;
      if (mPtr != nullptr && 0 == mpRefCnt->delRef_s())
      {
        mDeletor(mPtr);
        mPtr = nullptr;
        if (0 == mpRefCnt->getCnt_w())
        {
          delete mpRefCnt;
        }
        mpRefCnt = nullptr;
      }
      mPtr = src.mPtr;
      mpRefCnt = src.mpRefCnt;
      if (mPtr != nullptr)
      {
        mpRefCnt->addRef_s();
      }
      return *this;
    }

    shared_ptr(shared_ptr<T>&& _u)//移动构造函数
    {
      mPtr = _u.mPtr;
      mpRefCnt = _u.mpRefCnt;
      _u.mPtr = nullptr;
      _u.mpRefCnt = nullptr;
    }
    shared_ptr<T>& operator=(shared_ptr<T>&& _u)//移动赋值函数
    {
      if (this == &_u) return *this;
      if (this->mPtr != nullptr && 0 == mpRefCnt->delRef_s())
      {
        mDeletor(mPtr);
        mPtr = nullptr;
        if (0 == mpRefCnt->getCnt_w())
        {
          delete mpRefCnt;
        }
        mpRefCnt = nullptr;
      }
      mPtr = _u.mPtr;
      mpRefCnt = _u.mpRefCnt;
    }
    int use_count() const//返回引用该资源的强智能指针的个数
    {
      int cnt = 0;
      if (mpRefCnt != nullptr)
      {
        cnt = mpRefCnt->getCnt_s();
      }
      return cnt;
    }
    operator bool() const
    {
      return (mPtr != nullptr);
    }
    void reset(T* ptr)//重置函数
    {
      if (mPtr != nullptr && 0 == mpRefCnt->delRef_s())
      {
        mDeletor(mPtr);
        mPtr = nullptr;
        if (0 == mpRefCnt->getCnt_w())
        {
          delete mpRefCnt;
        }
        mpRefCnt = nullptr;
      }
      mPtr = ptr;
      mpRefCnt = nullptr;
      if (mPtr != nullptr)
      {
        mpRefCnt = new RefCnt<T>(mPtr);
      }
    }
    void swap(shared_ptr<T>& _X)//交换函数
    {
      std::swap(this->mPtr, _X.mPtr);
      std::swap(this->mpRefCnt, _X.mpRefCnt);
    }
    shared_ptr(const weak_ptr<T>& _w)//拿弱智能指针拷贝构造强智能指针
    {
      mPtr = _w.mPtr;
      mpRefCnt = _w.mpRefCnt;
      mpRefCnt->addRef_s();
    }
    friend class weak_ptr<T>;//友元
  private:
    T* mPtr;// obj , nullptr;
    lzy::RefCnt<T>* mpRefCnt;
    Deletor mDeletor;
  };

  template<class T>
  class weak_ptr//弱智能指针类
  {
  public:
    weak_ptr() :mPtr(nullptr), mpRefCnt(nullptr) {}
    weak_ptr(shared_ptr<T>& s) :mPtr(s.mPtr), mpRefCnt(s.mpRefCnt)//构造函数,监视强智能指针
    {
      if (mpRefCnt != nullptr)
      {
        mpRefCnt->addRef_w();
      }
    }
    ~weak_ptr()//析构函数
    {
      release();
    }
    weak_ptr(weak_ptr<T>& w) :mPtr(w.mPtr), mpRefCnt(w.mpRefCnt)//拷贝构造函数
    {
      if (mpRefCnt != nullptr)
      {
        mpRefCnt->addRef_w();
      }
    }
    weak_ptr<T>& operator=(const weak_ptr<T>& s)//赋值重载函数
    {
      release();
      mPtr = s.mPtr;
      mpRefCnt = s.mpRefCnt;
      mpRefCnt->addRef_w();
    }
    shared_ptr<T> lock() const//提升方法,提升为强智能指针
    {
      if (expired())//如果失效
      {
        return nullptr;
      }
      return shared_ptr<T>(*this);//提升成功
    }
    int use_const() const//弱智能指针的引用计数
    {
      return mpRefCnt->getCnt_s();
    }
    bool expired() const//判断是否失效
    {
      if (mpRefCnt != nullptr)
      {
        return mpRefCnt->getCnt_s() == 0;
      }
      return true;
    }
    friend class shared_ptr<T>;
  private:
    void release()//释放函数
    {
      if (mpRefCnt != nullptr)
      {
        mpRefCnt->delRef_w();
        if (mpRefCnt->getCnt_s() == 0 && 0 == mpRefCnt->getCnt_w())
        {
          delete mpRefCnt;
          mpRefCnt = nullptr;
        }
      }
      mPtr = nullptr;
      mpRefCnt = nullptr;
    }
    T* mPtr;
    RefCnt<T>* mpRefCnt;
  };


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值