可以打开

首页 » 常识 » 常识 » 聊聊C中的几种智能指针下
TUhjnbcbe - 2024/5/11 16:47:00

一:背景

我们聊到了C++的auto_ptr,有朋友说已经在C++17中被弃用了,感谢朋友提醒,今天我们来聊一下C++11中引入的几个智能指针。

unique_ptrshad_ptrweak_ptr

看看它们都怎么玩。

二:三大智能指针详解

1.unique_ptr

在说auto_ptr的时候聊过一个术语叫控制权转移,言外之意就是下面的代码会访问违例。

voidtest(){  int*i=newint(10);  auto_ptrintptr1(i);  auto_ptrintptr2=ptr1;//将ptr1的控制台送给了ptr2  cout*ptr1endl;}intmain(){  test();}

这段代码用了赋值运算符,可能是程序员的无心之举,却引来程序的崩溃,那能不能规避下这种无心的行为呢?当然是可以的,屏蔽掉auto_ptr中的赋值运算符不就可以了哈,C++中的unique_ptr就是这么实现的,可以看下源码。

classunique_ptr{public:  unique_ptr(constunique_ptr)=delete;  unique_ptroperator=(constunique_ptr)=delete;};

可以看到,unique_ptr将=,复制构造函数都给屏蔽了,所以再硬写的话,必然是报错。

2.shad_ptr

这个算是纯正的引用计数,高级语言中的引用跟踪经常会拿它做比较,说它存在循环引用等各种问题。

在循环引用之前,先说下它的简单用法。

voidtest(){  int*i=newint(10);  shad_ptrintptr1(i);  shad_ptrintptr2=ptr1;  shad_ptrintptr3=ptr2;  printf("ptr.fcnt=%d,ptr2.fcnt=%d,ptr3.fcnt=%d\n",                        ptr1.use_count(),                        ptr2.use_count(),                        ptr3.use_count());}intmain(){  test();}

再看下源码,大概在内部共同维护了对_Ref_count_base引用。

class_Ref_count_base{private:  _Atomic_counter_t_Uses=1;  _Atomic_counter_t_Weaks=1;}

很显然当所有的析构函数将_Uses降为0的时候就会对i进行释放,参考源码如下:

classshad_ptr:public_Ptr_base_Ty{  ~shad_ptr()noexcept{//leasesource    this-_Decf();  }}class_Ref_count_base{  void_Decf()noexcept{//decmentusecount    if(_MT_DECR(_Uses)==0){      _Destroy();      _Decwf();    }  }}

原理大概摸清楚了,接下来看下循环引用,它最大的问题就是让_Uses永远也不会为0,

#includeiostam#includestringusingnamespacestd;classBClass;classAClass{public:  inti=10;  shad_ptrBClassb;};classBClass{public:  inti=11;  shad_ptrAClassa;};voidtest(){  AClass*a=newAClass();  BClass*b=newBClass();  shad_ptrAClassaclass(a);  shad_ptrBClassbclass(b);  aclass-b=bclass;  bclass-a=aclass;  printf("a.fcnt=%d,b.fcnt=%d,a=%x,b=%x\n",aclass.use_count(),bclass.use_count(),(*a),(*b));}intmain(){  test();}

接下来可以在main方法结束的地方观察a,b所有的heap块的内存内容是否被释放?可以清楚的看到还在那里。。.如下图所示:

这就是循环引用造成的问题,这时候就需要用到weak_ptr了。

3.weak_ptr

弱引用就是它的引用不改变对原对象中_Uses的引用,接下来将AClass和BClass中的shad_ptr改成weak_ptr版。

classAClass{public:  inti=10;  weak_ptrBClassb;};classBClass{public:  inti=11;  weak_ptrAClassa;};

从图中可以看到,此时fcnt=1,再观察下地址0xf71a8的内容,可以发现已经被释放啦。

好了,今天我们就聊这么多,希望对大家有帮助。

1
查看完整版本: 聊聊C中的几种智能指针下