目录
基础部分
1、智能指针的引入
2、什么是智能指针
一、auto_ptr 自动指针
1、出现
2、原理
3、注意事项
二、scoped_ptr 守卫指针
1、出现
2、方法
1、出现
2、原理
3、循环引用
四、weak_ptr 弱指针
1、出现
2、原理
五、unique_ptr
补充:
在编程中常会有动态内存的开辟,而用完后会忘记释放;
在逻辑处理时也要十分严谨;
野指针的问题。因为一不小心就会有内存泄漏问题。内存泄漏会引发占用存储空间越来越多,最终用尽全部存储空间,整个系统崩溃。智能指针就是为了防止内存泄漏而引出的。
智能指针是一个类,用它的对象管理着申请的内存空间,并通过作用域、声明周期来保证申请内存的释放,从而防止出现内存泄漏
所谓的智能指针就是帮你管理指针,用完后自动释放 //手动开辟,系统释放
C++98时提出的,效果不是很好,于是才出现了其他的智能指针
所有权唯一
管理权转移(新的指针在拷贝构造或者赋值原来的指针时,会把原来的指针置为NULL,让新指针指向原来指针指向的空间,所以称之为自动指针)所以访问原来的指针时,程序会崩溃
(1)auto_ptr不能共享所有权
(2)auto_ptr不能指向数组
(3)auto_ptr不能作为容器的成员
(4)不能通过赋值操作来初始化auto_ptr
(5)不要把auto_ptr放入容器
所以尽量任何情况下也不用auto_ptr
因为auto_ptr的各方面都不行(在拷贝构造或者赋值运算后,访问原来的指针程序就会崩溃),scoped_ptr就是为了避免这种奔溃才出现的。scoped_ptr直接不允许进行拷贝构造和赋值运算符重载,故而没有释放两次导致崩溃的事情发生。
将拷贝构造和赋值运算符重载的声明给成私有,不给定义
假设我们在类外运用了拷贝构造和赋值运算,编译器会检查,发现这是不正确的。错误提示:无法访问private成员
shared_ptr是可以拷贝和赋值的,通过对管理一块空间的智能指针进行计数,只有当count == 0时,再进行释放
所有权不唯一
shared_ptr的管理机制其实并不复杂,就是对所管理的对象进行了引用计数,当新增一个shared_ptr对该对象进行管理时,就将该对象的引用计数加一;减少了一个shared_ptr对该对象进行管理时,就将该对象的引用计数减一,如果该对象的引用计数为0的时候,说明没有任何指针对其管理,才调用delete释放其所占的内存。这也是最常用的一种
shared_ptr可能会出现循环引用的问题
我们实例化两个shared_ptr对象,pa指向一块空间,pb指向另一块空间。那么按照shared_ptr的机制,此时pa和pb指针所指向的空间计数count都为1。但是假设两个shared_ptr的对象中还有next指针和prev指针。我们让pa中的next指针指向pb指向的空间时,pb所指向的空间中的count计数变为2;pb的prev指针指向pa指向的空间,pa所指向的空间计数count也变成了2.
当pa释放时,它所指向的空间计数count必须为0,此时,pb中的prev指针也指向该空间,只有当pb中的prev被释放了,pa才能被释放;
要释放pb中的prev指针,它指向的空间计数器count必须为0,此时pa中的next指针也指向该空间,只有当pa中的next指针被释放了,pb才能释放
这就是存在的循环引用问题
因为shared_ptr有循环引用的问题,weak_ptr就是为了解决循环引用而产生的,weak_ptr不会增加shared_ptr所指向空间的引用计数
弱指针并不修改对象的引用计数,这意味着弱指针引用它并不对对象的内存进行管理,在功能上类似于普通指针,然而一个比较大的区别,弱指针能检测到所管理的对象是否已经被释放,从而避免访问非法内存
类似于一个动态开辟的数组
由于可以用vector实现,所以用的不多,并且不存在于boost库
指一块被分配的内存既不能使用,又不能回收,直到进程结束
内存泄漏: 是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
一般我们所说的内存泄漏是指堆内存的泄漏,堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完成之后必须显示释放内存。应用程序一般使用malloc、realoc、new等函数从堆中分配到一块内存块,使用完成后,程序必须负责相应的释放。在C中使用free(),C++中delete、delete[]、free()。而Java中由于垃圾回收机制不用手动释放。
如果内存不能释放,这块内存就不能再次使用,我们就说这块内存泄漏了。
(1)常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。
(2)偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
(3)一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。
(4)隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。
从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到.
内存溢出:程序要求的内存,超出了系统所能分配的范围。如:我们用一个int型4字节的数据来装一个float型8字节的数据,就会产生内存溢出。不过我们在编程是可以强制类型转换int XX = (int)float;只取float 4字节数据给int.
RAII称为“资源获取就是初始化”,是c++等编程语言常用的管理资源
避免内存泄露的方法。它保证在任何情况下,
使用对象时先构造对象,最后析构对象。
了解智能指针就需要了解boost库,C++11引入的智能指针标准中,参考了boost库中对智能指针的实现