Effective Modern C++ 笔记 第四章 Smart Pointers

  1. Item 18: Use std::unique_ptr for exclusive-ownership resource management.
  2. Item 19: Use std::shared_ptr for shared-ownership resource management.
  3. Item 20: Use std::weak_ptr for std::shared_ptr-like pointers that can dangle.
  4. Item 21: Prefer std::make_unique and std::make_shared to direct use of new.
  5. Item 22: When using the Pimpl Idiom, define special member functions in the implementation file.


这一章主要讲unique_ptr, shared_ptr, weak_ptr, 读起来相对轻松,毕竟这些概念早已经广泛应用了。要点如下:

unique_ptr在默认的deleter情况下可以达到裸指针的大小。如果指定deleter会增加空间。shared_ptr相对来说overhead就会大些,shared_ptr除了维护指向object的指针,当然还需要维护一个“control block”。control block包含如引用计数,弱引用计数等相关信息。

如果自定义deleter,那么这个deleter的类型对于unique_ptr来说是必须的,它是模板参数之一也就是unique_ptr的类型信息的一部分。而shared_ptr则不需要,它只需要目标对象的类型。所以shared_ptr显然更灵活。如果两个unique_ptr是不同的deleter类型的话,它们的类型是不同的;而同类型的shared_ptr则完全可以有不同的deleter。

那么这么做的原因呢?没想太明白。查了下一个还可以的解释是: stackoverflow。也就是unique_ptr是以raw pointer为目标而不引入任何overhead的。引入deleter的类型信息就可以在编译期将unique_ptr的操作完全交给编译器进行进一步优化。

由于smart pointer的存在,消灭裸指针不仅是一个可选项而是必选项。如果同时使用smart pointer和裸指针就意味着小心踩坑(比如shared_ptr,你有一个raw pointer但是搞出两个control block在不同的shared_ptr里面。。。)。而对于shared_ptr来说,make_shared会是一种更高效的使用方式,原因在于前面提到了shared_ptr要维护control block,如果使用make_shared来同时完成object和control block的内存分配,就给了库代码很多的优化余地,比如把control block和object分配在一块内存。。。

另外c++里面很著名的一个指针就是this了。如果要对this使用shared_ptr,那么就需要继承自enable_shared_from_this并使用shared_from_this了。enable_shared_from_this代码如下:

  template<typename _Tp>
    class enable_shared_from_this
    {
    protected:
      constexpr enable_shared_from_this() noexcept { }

      enable_shared_from_this(const enable_shared_from_this&) noexcept { }

      enable_shared_from_this&
      operator=(const enable_shared_from_this&) noexcept
      { return *this; }

      ~enable_shared_from_this() { }

    public:
      shared_ptr<_Tp>
      shared_from_this()
      { return shared_ptr<_Tp>(this->_M_weak_this); }

      shared_ptr<const _Tp>
      shared_from_this() const
      { return shared_ptr<const _Tp>(this->_M_weak_this); }

    private:
      template<typename _Tp1>
	void
	_M_weak_assign(_Tp1* __p, const __shared_count<>& __n) const noexcept
	{ _M_weak_this._M_assign(__p, __n); }

      template<typename _Tp1>
	friend void
	__enable_shared_from_this_helper(const __shared_count<>& __pn,
					 const enable_shared_from_this* __pe,
					 const _Tp1* __px) noexcept
	{
	  if (__pe != 0)
	    __pe->_M_weak_assign(const_cast<_Tp1*>(__px), __pn);
	}

      mutable weak_ptr<_Tp>  _M_weak_this;
    };

假设类Test继承自enable_shared_from_this。enable_shared_from_this维护了一个weak_ptr,需要的时候就转一个shared_ptr出去。这个weak_ptr的对象指针,control block等都是通过__enable_shared_from_this_helper手动指定的。当对Test进行shared_ptr的构建操作时,会调用Test对象的__enable_shared_from_this_helper,将weak_ptr设置为正确的值,自然而然也就可以通过shared_from_this获得一个新的shared_ptr。

可以看出,调用shared_from_this之前,一定要已经存在Test的shared_ptr(control block已经存在了)。毕竟enable_shared_from_this和shared_from_this只是返回正确的shared_ptr,而不是创建正确的shared_ptr。

另外一个非常可疑的地方就是__enable_shared_from_this_helper的参数:const enable_shared_from_this* __pe,竟然没有模板参数。。。直接扔到stackoverflow,看解释: stackoverflow

再说weak_ptr,除了它带来的好处,一个问题是weak_ptr使得control block和object的生命周期变得不一样了,也就是存在weak_ptr但是不存在对应的shared_ptr时,control block的内存是无法回收的。control block和object分别回收似乎也没啥问题,但是如果两者的内存由于优化是放在一起的话。。。item21对这个问题进行了详细的介绍。

item22 pimpl的例子也很有趣。部分可以说明unique_ptr类型中包含deleter类型信息的一些影响。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值