Effective Modern C++:条款19

Aki 发布于 2023-01-14 251 次阅读


19使用shared_ptr管理具备共享所有权的资源:

shared_ptr通过共享所有权来管理生存周期,没有特定的shared_ptr拥有该对象当最后一个涉及到该对象的指针不再涉及到它时(即引用计数变为0),就会析构该对象

引用计数的影响:

  • shared_ptr的尺寸是裸指针的两倍
  • 引用计数的内存必须动态分配
  • 引用计数的递增和递减是原子操作
  • shared_ptr的移动操作快于复制操作,这是由于移动操作不涉及引用计数的操作

shared_ptr底层结构:

使用自定义析构器不会改变shared_ptr的尺寸,这是由于shared_ptr的特殊结构所致。

shared_ptr<T>由两部分组成:

  • 指涉到T型别对象的指针
  • 指涉到控制块的指针

控制块包括:

  • 引用计数
  • 其他数据(自定义析构器等)

控制块创建规则

  • make_shared总会建一个控制块
  • 由unique_ptr等专属所有权的指针创建一个shanred_ptr时会创建一个控制块
  • 由裸指针生成一个shared_ptr时会创建一个控制块

控制块对指针的影响:

auto w = new int{ 10 };
shared_ptr<int>p1{ w };
shared_ptr<int>p2{ w };

形如此种操作就会导致为裸指针w生成两个控制块,即会析构两次指针,造成程序崩溃

shared_ptr使用建议:

应避免将裸指针作为参数生成shared_ptr,若必须使用裸指针生成,最好使用右值作为参数生成,即使用new

shared_ptr<int> p1(new int{});  

此种方法会大大降低为一个裸指针生成两个控制块的概率。或使用

shared_ptr<int> p2(p1); 

这样w与w1使用的是同一个控制块

请记住:

  • std::shared_ptr提供和垃圾回收机制差不多方便的方法,来对任意的资源进行共享语义的生命周期管理。
  • 比起std::unique_ptr,std::shared_ptr对象常常是它的两倍大,需要承担控制块的间接费用,并且需要原子的引用计数操作。
  • 默认的资源销毁操作是通过delete进行的,但是自定义deleter是支持的。deleter的类型不会影响到std::shared_ptr的类型。
  • 避免从原始指针类型的变量来创建std::shared_ptr。