智能指针(内存泄漏)
一、RALL
RALL的核心概念:
资源获取即初始化:资源的分配与对象的初始化绑定在一起,资源的释放与对象的销毁绑定在一起。
不是所有智能指针都用这个思想
可以有效避免死锁问题
二、智能指针
通过将new出的对象教给有生命周期的对象处理。
在对象过期时,会自动调用它的析构函数来删除指向的空间
=>避免空间泄漏
三、auto_ptr
auto_ptr 是c++ 98定义的智能指针模板,其定义了管理指针的对象,可以将new 获得(直接或间接)的地址赋给这种对象。当对象过期时,其析构函数将使用delete 来释放内存用法:
头文件: #include < memory >
用 法: auto_ptr<类型> 变量名(new 类型)
例如:auto_ptr<Test> test<new Test>
智能指针可以像普通指针那样使用,因为重载了*和->,*返回普通函数,->返回指针对象。
智能指针三个常用函数
1,get() 获得智能指针托管的指针地址
2、release() 取消智能指针对动态内存的托管
=>改为由管理员进行管理
3、reset() 重置智能指针托管的内存地址,如果地址不一样,原来的会被析构掉,不指定则为nullptr
使用建议:
1、尽可能不要使用auto_ptr变量定义为全局变量或者指针
2、不要把auto_ptr指针赋值给一个同类型的另一个智能指针
原因:复制或赋值的时候都会改变资源的所有权
在STL容器中使用auto_ptr同样存在重大风险,因为容器内元素必须可复制和可赋值。
不支持数组的内存管理
因此产生了unique_ptr
四、unique_ptr特性:
1、两个指针不能指向同一个资源
2、无法进行左值unique_ptr复制构造,也无法进行左值复制构造,但允许临时右值赋值构造
3、在使用STL容器的时候不允许出现赋值
4、支持数组的内存管理
但是unique_ptr和auto_ptr都存在排他性,即一个指针只能由一个智能指针所管理,由此引出shared_ptr
注意:他有第二个参数,第二个参数可以传一个删除器的仿函数
五、shared_ptr
通过引用计数来解决排他性问题
当复制或者拷贝时,计数+1,析构时-1,如果计数为0,就释放这段空间。
use_count() 来获得当前托管指针的引用计数
(1)初始化使用make_shared(对象)来初始化
例如:
shared_ptr up=make_shared_ptr<int>
(2)主动释放对象:
shared_ptr<int> up(new int(10));up=nullptr;
(3)交换(交换p1和p2管理的对象,引用计数不变)
std::swap(p1,p2);p1.swap(p2);
使用注意:小心因果循环引用造成无法释放
要避免对象交互使用智能指针的情况
由此引出弱指针的智能指针
六、weak_ptr
用以配合shared_ptr而引入
在构造和析构的时候,引用计数不变
它只能从一个shared_ptr或另一个weak_ptr对象构造·
使用:
weak_ptr wp;空
weak_ptr wp(test);使用共享指针构造
test1=test 允许共享指针赋值给弱指针
可以使用use_count()来获得引用的个数.
不支持 * 和-> 对指针的访问
可以转换为lock()
expired()函数 判断当前weak_ptr是否还有托管对象,有则false,无则ture。
六、智能指针的使用注意
不要把一个原生指针给多个智能指针管理;
int *x = new int(10);
unique_ptr< int > up1(x);
unique_ptr< int > up2(x);
// 警告! 以上代码使up1 up2指向同一个内存,非常危险
或以下形式:
up1.reset(x);
up2.reset(x);
记得使用u.release()的返回值;
在调用u.release()时是不会释放u所指的内存的,这时返回值就是对这块内存的唯一索引,如果没有使用这个返回值释放内存或是保存起来,这块内存就泄漏了.
禁止delete 智能指针get 函数返回的指针;
如果我们主动释放掉get 函数获得的指针,那么智能 指针内部的指针就变成野指针了,析构时造成重复释放,带来严重后果!
禁止用任何类型智能指针get 函数返回的指针去初始化另外一个智能指针!