EP02.new和make_shared区别

接口使用

#include <iostream>
#include <memory>
#include <type_traits>

struct Foo
{
    Foo(int i) : i(i) {} 
    int i;
};

int main()
{
    auto sp1 = std::make_shared<Foo>(12);    // 方式1
    std::shared_ptr<Foo> sp2(new Foo(30));   // 方式2

    static_assert(std::is_same<decltype(sp1), std::shared_ptr<Foo>>::value);
    static_assert(std::is_same<decltype(sp2), std::shared_ptr<Foo>>::value);

    std::cout << sp1->i << '\n';
    std::cout << sp2->i << '\n';
}
  • 通过方式2,是先在堆上分配一块内存,然后在堆上再建一个智能指针控制块,这两个东西是不连续的,会造成内存碎片化
  • 通过方式1,是直接在堆上新建一块足够大的内存,其中包含两部分,上面是内存(用来使用),下面是控制块(包含引用计数),然后用Foo的构造函数去初始化分配的内存(分配一块内存的步骤:先分配内存,再进分配的内存调用构造函数进行构造,构造完毕才能使用)

new方式

// 构造函数初始化列表_M_refcount(__p) 这里会进行内存分配
      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);
	}

	template<typename _Ptr>
        explicit
	__shared_count(_Ptr __p) : _M_pi(0)
	{
	  __try
	    {
	      _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);
	    }
	  __catch(...)
	    {
	      delete __p;
	      __throw_exception_again;
	    }
	}

make_shared接口

auto sp1 = std::make_shared<Foo>(12);调用堆栈

–> make_shared

–> allocate_shared

​ --> __shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a, _Args&&... __args)

–> operator=

// ref: gcc-4.8.5\libstdc++-v3\include\bits\shared_ptr.h

  /**
   *  @brief  Create an object that is owned by a shared_ptr.
   *  @param  __args  Arguments for the @a _Tp object's constructor.
   *  @return A shared_ptr that owns the newly created object.
   *  @throw  std::bad_alloc, or an exception thrown from the
   *          constructor of @a _Tp.
   */
  template<typename _Tp, typename... _Args>
    inline shared_ptr<_Tp>
    make_shared(_Args&&... __args)
    {
      typedef typename std::remove_const<_Tp>::type _Tp_nc;
      return std::allocate_shared<_Tp>(std::allocator<_Tp_nc>(),
				       std::forward<_Args>(__args)...);
    }

 /**
   *  @brief  Create an object that is owned by a shared_ptr.
   *  @param  __a     An allocator.
   *  @param  __args  Arguments for the @a _Tp object's constructor.
   *  @return A shared_ptr that owns the newly created object.
   *  @throw  An exception thrown from @a _Alloc::allocate or from the
   *          constructor of @a _Tp.
   *
   *  A copy of @a __a will be used to allocate memory for the shared_ptr
   *  and the new object.
   */
  template<typename _Tp, typename _Alloc, typename... _Args>
    inline shared_ptr<_Tp>
    allocate_shared(const _Alloc& __a, _Args&&... __args)
    {
      return shared_ptr<_Tp>(_Sp_make_shared_tag(), __a,
			     std::forward<_Args>(__args)...);
    }

      template<class _Tp1>
	shared_ptr&
	operator=(shared_ptr<_Tp1>&& __r) noexcept
	{
	  this->__shared_ptr<_Tp>::operator=(std::move(__r));
	  return *this;
	}
	
	template<typename _Alloc, typename... _Args>
	__shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
		     _Args&&... __args)
	: _M_ptr(), _M_refcount()
        {
	  typedef typename _Alloc::template rebind<_Tp>::other _Alloc2;
          _Deleter<_Alloc2> __del = { _Alloc2(__a) };
	  typedef allocator_traits<_Alloc2> __traits;
          _M_ptr = __traits::allocate(__del._M_alloc, 1);
	  __try
	    {
	      // _GLIBCXX_RESOLVE_LIB_DEFECTS
	      // 2070. allocate_shared should use allocator_traits<A>::construct
	      __traits::construct(__del._M_alloc, _M_ptr,
		                  std::forward<_Args>(__args)...);
	    }
	  __catch(...)
	    {
	      __traits::deallocate(__del._M_alloc, _M_ptr, 1);
	      __throw_exception_again;
	    }
          __shared_count<_Lp> __count(_M_ptr, __del, __del._M_alloc);
          _M_refcount._M_swap(__count);
	  __enable_shared_from_this_helper(_M_refcount, _M_ptr, _M_ptr);
        }

性能测试

测试用例

#include <iostream>
#include <memory>
#include <time.h>

struct Foo
{
    Foo(int i) : i(i) {}
    int i;
    short b;
    char buf[4];
    char arr[28];
    bool check;
};

uint64_t timespec_diff(timespec t1, timespec t2)
{
    return (t2.tv_sec - t1.tv_sec) * 1000000000ULL + t2.tv_nsec - t1.tv_nsec;
}

int main(int argc, char* argv[])
{
    constexpr int kLoop = 10000;
    timespec t1, t2, t3;
    clock_gettime(CLOCK_MONOTONIC, &t1);
    for (int i = 0; i < kLoop; ++i)
    {
        auto sp1 = std::make_shared<Foo>(22);
    }
    clock_gettime(CLOCK_MONOTONIC, &t2);
    for (int i = 0; i < kLoop; ++i)
    {
        std::shared_ptr<Foo> sp2(new Foo(22));
    }
    clock_gettime(CLOCK_MONOTONIC, &t3);

    std::cout << "new cost time: " << timespec_diff(t2, t3) * 1.0 / kLoop << "ns" << std::endl;
    std::cout << "make_shared cost time: " << timespec_diff(t1, t2) * 1.0 / kLoop << "ns" << std::endl;
    return 0;
}

时延数据

场次newmake_shared
-O0优化109.873ns286.667ns
-O1优化48.7914ns26.6106ns
-O2优化49.4341ns28.6477ns

从测试数据看出,make_shared比new快一倍左右。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Erice_s

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值