探讨智能指针
探讨智能指针
C++中,动态内存的管理需要依靠一对运算符来完成:new,在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象进行初始化;delete,接受一个动态对象的指针,销毁该对象,释放与之关联的内存。
但是,动态内存的使用很容易出现问题。
- 当忘记释放内存时,就会造成内存泄漏;
- 若上有指针引用内存,我们就提前释放了该内存,就会产生引用了非法内存的指针(悬空指针)。
为了更容易地使用动态内存,新的标准库提供了两种智能指针类型来管理动态对象。(定义在memory头文件中)
shared_ptr
允许多个指针指向同一个对象;unique_ptr
则独占所指向的对象;weak_ptr
,是一种弱引用,指向shared_ptr
管理的对象。
shared_ptr
1 |
|
需要特别注意的是,当调用拷贝构造函数后,引用计数递增。相当于有两个指针指向对象;
当进行赋值运算时,如p=q
,q的引用计数递增,p的引用计数递减。两个指针都指向q的所指对象。
shared_ptr自动销毁所管理的对象 当指向一个对象的最后一个shared_ptr被销毁时,shared_ptr类会自动销毁此对象,它是通过析构函数完成销毁工作的。shared_ptr的析构函数会递减它所指向的对象的引用计数。如果引用计数变为0,shared_ptr的析构函数就会销毁对象,并释放它所占用的内存。
1 |
|
shared_ptr还会自动释放相关联的内存 当动态对象不再被使用时,shared_ptr类还会自动释放动态对象,这一特性使得动态内存的使用变得非常容易。如果你将shared_ptr存放于一个容器中,而后不再需要全部元素,而只使用其中一部分,要记得用erase删除不再需要的那些元素。
程序使用动态内存的原因: (1)程序不知道自己需要使用多少对象 (2)程序不知道所需对象的准确类型 (3)程序需要在多个对象间共享数据
定义和改变shared_ptr的其他方法:
unique_ptr
一个unique_ptr“拥有”它所指向的对象,某个时刻只能有一个unique_ptr指向一个给定的对象。没有类似make_shared
的函数,所以定义unique_ptr的时候要绑定到一个new返回的指针上。
1 |
|
unique_ptr不支持拷贝、赋值操作
unique_ptr所有权的转移
1 |
|
不能拷贝unique_ptr有一个例外:我们可以拷贝或赋值一个将要被销毁的unique_ptr.最常见的例子是从函数返回一个unique_ptr.
1 |
|
还可以返回一个局部对象的拷贝:
1 |
|
weak_ptr
weak_ptr是一种不控制所指向对象生存期的智能指针,它指向一个由shared_ptr管理的对象。将一个weak_ptr绑定到shared_ptr不会改变引用计数。
主要是用于解决shared_ptr循环引用的问题。
1 |
|
由于对象可能不存在,我们不能使用weak_ptr直接访问对象,而必须调用lock,此函数检查weak_ptr指向的对象是否存在。如果存在,lock返回一个指向共享对象的shared_ptr,如果不存在,lock将返回一个空指针。
面试官曾经问过。如果shared_ptr都已经释放掉了,那么weak_ptr还能够访问哪个对象吗?
将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放。即使有weak_ptr指向对象,对象也还是会被释放。在实际访问中,可以根据lock的返回值来判断对象是否还存在。
shared_ptr可以直接赋值给一个weak_ptr,那么如何使用weak_ptr初始化一个shared_ptr呢?
使用lock函数
1 |
|
其他问题
参考资料
[1]《C++ Primer中文版 第五版》
[2] https://blog.csdn.net/flowing_wind/article/details/81301001