在C
, Cpp
, Rust
中的RAII
设计模式
RAII
是Resource Acquisition is Initialization
的首字母缩写词。但,它的内容丰富,可不如首字母展开词汇那样意思直白。甚至,若直接去理解它的字面含义,你或许还会有一种不识其言的莫名其妙感。
【RAII
设计模式】是将操作系统资源(物理概念)映射为代码内的对象(逻辑概念)。然后,自然而然地,
- 资源调度的生命周期 映射为 对象的生命周期
- 资源使用的申请环节 映射为 对象的构造函数 --- 对象生,则资源在。
- 资源释放的归还环节 映射为 对象的析构函数 --- 对象亡,则资源灭。
将对资源的分配/回收操作代码从散乱的【业务代码】里抽象出来,并隐藏于【变量-生命周期管理】的成熟架构之后。而变量管理的万般规则都服务于一个主旨:超出了作用域,就执行析构函数,给我释放掉。于是,就有
- 变量所属作用域终结 --- 如何终结不重要。管它是异常终止
throw
,提前return
,还是“寿终正寝”,这都不重要。 - 变量释放
- 系统资源回收 --- 只要资源随着变量一起被释放,那就绝对的“异常安全
exception safe
”。
从code review
的视角来审视,
- 业务代码也看着清爽 --- 少了随处的
alloc
/new
,与需要烧脑才能搞明白的dealloc
/delete
出现位置。 - 编译器也有更高级的事可做 --- 特别指
Rust
。那繁杂的所有权规则,开发者都能给绕晕。
这岂不是【业务开发的码农】与【编译器大师】的双赢局面。和皆大欢喜美好结局。
C
不支持RAII
。若实现这个设计模式,开发者准备完全自己动手丰衣足食吧。或者寻找第三方库。Cpp
从98
版开始,标准库提供了对RAII
的支持。但,需要调用std::scoped***()
,std::make_unique()
,std::make_shared()
等专用构造器来意图明确地编码。同时,开发者还得随时警惕着遗留代码里的new
和delete
的非RAII
代码(这类代码一般是非异常安全的not exception safe
)。- 在
Rust
里,对【内存/互斥锁/文件句柄】的分配与回收已经和Rust
【所有权变量】的生命周期完全耦合在一起了。RAII
被实现为语言规范的一部分,也是被强制要求的编码范式,开发者根本就没得选。包括对数据库连接的管理 --- 至少,从第三方库暴露出来的接口来看(源码没有研究过),其调用套路还是RAII
风格的。
当Rust
所有权变量超出了作用域时,
- 变量自身会被释放
- 该变量的析构函数也会自动释放被映射给它的资源
而这个过程是没有人工介入的。当然,你也可以借助std::mem::drop()
函数来提早终结(实现了Drop Trait
的)【所有权变量】的生命周期和释放系统资源。但,这对RAII
在Rust
里的全面落地没有影响,仅能算是对应用灵活性的有益补充。
1
共 3 条评论, 1 页
评论区
写评论学到了
涨姿势了
写的非常明白,手动点赞