前言
早期编写的C++是有缺陷的,举些例子。比如裸指针满天飞,多线程的数据竞争,双重释放等等。但如今的C++正在努力改善这些缺陷,RAII范式的编程在C++比重逐步增加。RAII(Resource Acquisition Is Initialization)是C++之父Bjarne Stroustrup在设计C++的时候就引入了。即:资源获取即初始化。通俗点,在对象创建的时候获取资源,在对象销毁的时候释放资源。确保内存的安全性。指针shared_ptr就是其中的杰作,下面也会讲到。
本篇除了RAII之外,还会分析下其析构函数的关联。代码部分,经过C++20测试,均可跑通,可直接用。
RAII操作例子
一个非常简单的RAII操作,我们初始化对象的时候打开了文件资源。然后在离开对象的作用域的时候,会调用析构函数释放(关闭)文件资源,例子如下:
File对象的构造函数里面打开文件,上面代码运行的结果如下:
图片
在File对象f离开作用域也即是try块的结尾大括号处,会调用析构函数,关闭文件。
关于这点我们lldb验证下,且简略分析下其原理。在~File()析构函数下断,其堆栈是在RAII.c:36也即是try块大括号结尾的地方调用了析构函数。
如下:
当我们运行到try块收尾大括号处,看此时程序刚好调用了File::~File
也即是代码:
RAII风格指针
现代C++的几个指针
- std::unique_ptr:独占所有权的智能指针。一个 unique_ptr 只能有一个指针指向资源,因此它不支持复制,只支持转移所有权。
- std::shared_ptr:共享所有权的智能指针。多个 shared_ptr 可以共享对资源的所有权,只有最后一个指针被销毁时,资源才会被释放。
- std::weak_ptr:一种不影响资源生命周期的智能指针,用来打破循环引用的问题
我们也来观察下RAII指针自动调用析构函数释放的例子
它的结果如下,同样的析构函数在离开作用域释放
图片
结尾
RAII并不是一个新鲜的特性,而是古早就有的一种范式。上面例子展示了对象创建的时候获取资源,对象销毁的时候释放资源的例子。
我们只需要写好代码的规范,其它的编译器都给做了,比如析构函数的调用等。这种操作,有效的防范了部分内存泄露的可能性。