智能指针是C++11引入的,比裸指针更为强大的指针。主要作用是用来完成一定程度上的内存资源管理自动化。
unique_ptr
unique_ptr
实现专属所有权功能。unique_ptr
不允许拷贝,只允许移动,保证了没有其他的指针指向unique_ptr
指向的对象。unique_ptr
被析构时,其析构函数会主动析构所指向的对象。
默认unique_ptr
使用delete
析构对象,不过它也支持自定义析构器。添加自定义析构器可能会增加unique_ptr
的大小,在默认状态下,unique_ptr
和裸指针的性能和大小是一张的。
同时unique_ptr
可以支持转换成shared_ptr
,所以在不知道用什么智能指针的情况下,直接用unique_ptr
就完事了。
可以使用make_unique
来创建一个unique_ptr
。
shared_ptr
shared_ptr
实现共享所有权功能,内部维护了一个引用计数,只有当引用计数为0时,该shared_ptr
被析构才会调用内部指向对象的析构函数。
对shared_ptr
的复制,会使得其引用计数+1,对其的析构会使得引用计数-1,而对其进行移动,则不会修改引用计数。
shared_ptr
同样默认使用delete进行析构,也支持自定义析构器,但是与unique_ptr
不同,对其进行自定义析构器不会改变shared_ptr
的大小。
shared_ptr
本身的尺寸是普通指针的两倍,因为其内部实际上维护了两个指针。第二个指针会指向一个叫做控制块的数据结构,里面维护了许多信息。
- 当
shared_ptr
第一次被make出来时,它会创建一个控制块。 - 当
shared_ptr
从unique_ptr
转化过来时,也会创建一个控制块。 - 当
shared_ptr
从一个裸指针转化过来时,也会创建一个控制块。
其中,从裸指针转换成shared_ptr
是最危险的,因为你可以转换任意多次,这会导致拥有对同一个对象的若干个控制块,而每一个控制块的引用计数归0时都会引发一次析构,也就是会导致多重析构的结构。所以实践中尽量避免。
weak_ptr
weak_ptr
属于是shared_ptr
的补丁。这么说是因为,shared_ptr
有一个无法绕过的槛,循环引用。假设你有两个shared_ptr
,分别是A和B。令A指向B,令B指向A,那么此时双方的引用计数永远都是1,也就是永远都不会析构,已经达成了事实上的内存泄漏。
但是这种相互引用的需求本身是真实存在的,就比如说图数据结构,一个节点可以被其他节点引用,同样也会引用很多其他的节点。所以在这种情况下,shared_ptr
行不通,那就要使用weak_ptr
。
weak_ptr
不会影响shared_ptr
的引用计数,可以从shared_ptr
中创建一个weak_ptr
出来。而weak_ptr
就具有检测这个shared_ptr
是否为空的功能,并且可以根据需要,返回这个shared_ptr
,使得你可以访问weak_ptr
所指向的对象。