Effective Modern C++ 之 shared_ptr

我们前面介绍了unique_ptr智能指针,它对它所指向的对象资源具有专属所有权。这个就直接导致unique_ptr是无法进行复制操作的。有没有一种智能指针对象资源不具有专属所有权,也就是它可以进行复制操作。当然有的。那就是shared_ptr智能指针。shared_ptr也是对裸指针进行包装的类。

  • shared_ptr智能指针对它所指涉的对象资源具有共享所有权,也就是说指涉到该对象资源的所有的shared_ptr共同协作,确保在不再需要该对象的时刻将其进行析构。当最后一个指涉到该资源的shared_ptr不在指涉到对象资源时,该shared_ptr会对该对象资源进行析构。怎么判断是否是最后一个shared_ptr指涉到该对象资源呢?
  • 引用计数可以完美解决这个问题。shared_ptr可以通过访问该对象资源的引用计数来确定是否是最后一个shared_ptr指涉到该对象资源。
  • 我们都知道shared_ptr智能指针底层要维护一个指涉到对象资源的裸指针,那么引用计数是怎么存储的呢?shared_ptr内部既包含一个指涉对象资源的裸指针,也包含了指涉到对象资源的引用计数的裸指针。因此,shared_ptr的尺寸是裸指针的两倍。
  • 因为shared_ptr智能指针对它所指涉的对象的资源具有共享所有权,所以shared_ptr可以进行复制操作。shared_ptr智能指针的构造函数会增加对象资源的引用计数,其析构函数会减少对象资源的引用计数。但是移动构造函数却不会导致引用计数发生改变。因为移动操作会析构源内存空间里面的对象资源。
  • 我们都知道unique_ptr可以自行定义删除器,其删除器的大小会影响unique_ptr的尺寸大小,这是因为unique_pt的删除器的型别是unique_ptr型别的一部分。shared_ptr也可以自行定义删除器,但是删除器的大小不会影响shared_ptr的寸尺大小。因为shared_ptr的删除器型别不是shared_ptr型别的一部分。
  • shared_ptr的删除器既然不是shared_ptr型别的一部分,那么删除器要怎么存储呢?我们刚刚讲过shared_ptr底层还维护一个指涉到对象资源的引用计数的裸指针,其实该裸指针指涉到一个控制块。该控制块包括:引用计数,弱计数(对weak_ptr讲解时会提到)和其他数据(包括自定义删除器,分配器等)。
  • 控制块的创建有以下的规则(当我们为对象资源分配内存空间时,总会创建控制块):
  1. 使用make_shared来创建shared_ptr总是创建一个控制块。
  2. 从具备专属所有权的指针(unique_ptr智能指针)出发构造一个shared_ptr时,会创建一个控制块。
  3. shared_ptr构造函数使用裸指针作为实参进行调用时,会创建一个控制块。
  • 当我们使用裸指针创建shared_ptr,可能会出现创建多个控制块,一个对象资源维护多个引用计数,便会导致该对象资源会多次被析构,从而出现未定义行为。因此,我们应该:第一,尽可能的避免使用裸指针创建shared_ptr。第二,使用new 运算符的结果来创建shared_ptr。(后面会专门的进行讨论)
发布了78 篇原创文章 · 获赞 11 · 访问量 5077

猜你喜欢

转载自blog.csdn.net/qq_43145594/article/details/104231802