C++总结2—shared_ptr交叉引用及多线程安全问题

智能指针是存储指向动态分配对象指针的类,用于生存期控制;能够确保正确销毁动态分配的内存,防止内存泄露。本博文参考博客https://blog.csdn.net/yusiguyuan/article/details/40628805

(1)智能指针的分类

1.不带引用计数的智能指针auto_ptr 、unique_ptr、 scoped_ptr

2.带引用计数的智能指针shared_ptr强智能指针、weak_ptr弱智能指针;

(2)不带引用计数的智能指针释放内存

1.auto_ptr

它的结构中有两个成员:_ptr和owns,只有获得对引用资源的管理权,才有权再出作用域之后释放资源;实现了拥有权限的指针可以释放资源,但是只能管理一块内存,而实际中,我们设计出一块资源可以由多个指针引用的情况
每次创建类的新对象时,初始化指针并将引用计数置为1;当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;调用析构函数时,析构函数减少引用计数(如果引用计数减至0,则删除基础对象)。代码示例如下:

template <typename T>
class Auto_Ptr
{

    public:
    //构造函数
      Auto_Ptr (T *ptr = NULL,bool own = false):_ptr(ptr),owner(own){}
    //析构函数
      ~Auto_Ptr(){if(owner) delete _ptr}
    //*运算符重载函数
       T& operator *(){return *_ptr;}
       const T& operator *(){return *_ptr;}
    //->运算符重载函数
       T* operator ->(){return _ptr;}
    //拷贝构造函数
      Auto_Ptr(const Auto_Ptr<T> &src)
      {
          src.release();
          ptr = src._ptr;
      }
    //改变所有权
      void release()const
      {
         ((Auto_Ptr<T>*)this)->owner = false;
      }
	private:
	  T *_ptr;
	  bool owner;

}
void main
{
   auto_ptr<A> ptr1(new A());
   auto_ptr<B> ptr2 = ptr1;
   vector<auto_ptr<int>> vec;//erro
}

当这两行代码执行完后,ptr1已经不再指向A这个对象,并且ptr1=NULL,ptr1对A对象的所有权已经转移给了ptr2,也就不能通过ptr1调用该类的方法。

不能将auto_ptr类型的指针作为STL容器的元素。因为容器避免不了直接拷贝构造和互相赋值。auto_ptr的这种特性会给STL容器的使用造成很大的麻烦。

(3)为什么shared_ptr在多线程下要考虑安全问题?

本次讲解主要以Boost库中的shared_ptr为例,首先先了解一下shared_ptr的结构设计,如下图所示:

 现在有以下几行代码

shared_ptr<class> x(new class);
shared_ptr<class> y = x;

第二行代码的执行分为两步:先复制_ptr,再复制ref_count,所以不会发生同时(原子)发生;两步骤如下图所示:

所以当出现在多线程条件下时,

考虑一个简单的场景,有 3 个 shared_ptr<Foo> 对象 x、y、z:

shared_ptr<class> z(new class); // 线程之间共享的 shared_ptr

shared_ptr<class> x; // 线程 A 的局部变量

shared_ptr<class> y(new class); // 线程 B 的局部变量

线程执行顺序如下:A线程执行x = z,并且执行完第一步后切换B进程执行z = y;则图解如下:

从上图中可以看到如果先复制_ptr,再复制ref_count会造成x._ptr成了空悬指针,所以存在线程安全问题;接下来的图解讨论的是如果先进行ref_count复制,再复制_ptr会存在什么安全问题:

从代码执行结果来看应该为X指向了Z引用的资源,class1的引用计数为2;Z指向了Y引用的资源,class2的引用计数为2;所以此种情况正确;

由以上的讨论得出shared_ptr在多线程中必须进行加锁控制,注意安全问题。

猜你喜欢

转载自blog.csdn.net/weixin_41966991/article/details/81071507