智能指针
普通指针出现的错误
- 内存泄漏:一个指针指向一块动态分配的内存,当该指针离开了所在的作用域,且程序结束后不进行释放,则会导致内存泄漏
- 悬空指针:指针指向了已经被释放的区域
- 野指针:指针未初始化使其指向有效内存区域
智能指针
智能指针是一个对象,封装了多态对象指针,可以有效避免上述情况
智能指针会自动申请内存,并在使用结束后释放内存
C++中存在封装了三种智能指针
- unique_ptr
- shared_ptr
- weak+ptr
unique_ptr
unique_ptr与管理对象是一对一的关系
创建
unique_ptr(A) ptr1(new A(参数))
unique_ptr(A) ptr1 =make_unique<A>(参数)(该方法较为安全)
其中A为类名
1 |
|
1 | 14.35 |
这里智能指针可以像普通指针一样使用,直接调用成员
离开作用域后,会自动销毁,调用析构函数释放指向的对象
注意:unique_ptr不能使用拷贝构造,也不能被赋值
成员函数
T* get();:获得所管理对象的指针T* operator->();:重载间接成员运算符,调用get()函数,返回所管理对象指针T& operator*();:重载解引用运算符,返回所管理对象的引用T* release();:解除对封装对象的管理,返回对象指针void reset(T* newObj):删除原有对象,接管新对象void swap(unique_ptr<T>& other):与其他unique_ptr对象交换所管理的对象move():转移指针所管理对象的所有权(转移后先前的指针就是野指针了)
优点
安全,且开销(时间与空间)与普通指针差距不大,成员函数带来的额外开销也不大,符合RAII
应用
适用于使用普通指针的地方,如容器
1 | struct Packet{ |
shared_ptr
多个shared_ptr通过一个共同的引用计数器来管理同一个对象
创建
shared_ptr(A) ptr1(new A(参数))
shared_ptr(A) ptr1 =make_shared<A>(参数)(该方法较为安全)
其中A为类名
控制块
shared_ptr需要分配另一块内存用来存储引用计数
当引用计数为0,即所有指向当前引用的指针都消失后,当前类才会被删除
成员函数
shared_ptr没有release方法
long use_count():获取有多少指针管理同一个对象bool unique():返回use_count()是否为1
类型转换
dynamic_pointer_cast<>()static_pointer_cast<>()const_pointer_cast<>()
循环引用
使用shared_ptr时可能会出现循环引用的情况,如在使用容器时
此时的引用计数会变为2,但当某个指针离开时只会见一,导致无法自动删除对象导致内存泄漏
我们可以使用weak_ptr来避免这种情况
1 |
|
weak_ptr
weak_ptr需要结合shared_ptr来使用
可以将一个shared_ptr对象作为构造函数参数初始化,或直接赋值
weak_ptr只对shared_ptr管理的对象进行观测,不改变对象的引用计数
可以通过对weak_ptr使用lock()函数,来获得一个shared_ptr以获得封装对象的控制权
若该shared_ptr非空,说明可用,且增加一次引用计数,在离开作用域前可以保证所管理对象是有效的
1 |
|
离开内部作用域后,对象的引用计数变为0,此时被析构,故wp1指向了空位置,可以判断对象有效性
使用expired()方法可以询问一个weak_ptr是否有效