RAII
2009-06-08 08:32:23 来源:WEB开发网显而易见,对于资源是否有效的判断已经使得程序员是否疲惫,而且,他们还需要不停的维护资源的指针,只要任何一步出错,程序都将变得脆弱,更作用的是,不但编写这样的程序不会有任何快感,使用这样的代码也十分郁闷,比如调用 GetChar 的时候,需要当心函数抛出的来异常,不断的写 try catch(如果使用 error codes 来表示错误,也需要不断的判断函数执行是否出错),在一些复杂的情况下,更加让人抓狂:
bool AddGroup(int idUser)
{
// 检查 idUser 是否允许加入组
// ...
// 检查成功,允许加入,扣去入会费
SpendUserMoney(idUser, 10000);
// 对于入会成功用户增加一个等级
AddUserLevel(idUser);
// 等等操作
// 将其写入文件中
try
{
// 在文件中写入用户当前等级,入会花费等信息
file.Write("xxx");
} catch (const Open_first&)
{
// 异常出现
// 恢复现场
AwardUserMoney(10000);
ReduceUserLevel(idUser);
// 等等
}
}
由上例可见,为了处理异常情况而做的工作太大,而且我们每次调用时都要进行相似的处理。虽然上例不一定完全合乎实际情况,或许你认为它还有改良的空间,不过无论如何,我们难免要做太多多余的工作。
自此,已经谈完了 RAII 设计方式的好处,那么下面谈谈应该注意一些什么:
1. 如果没有必要,应该禁止复制。
如果没有必要应该禁用复制构造函数和赋值操作符,这点很重要,如果没有按需要定义复制构造函数和赋值操作符,那么得到的结果通常是:非内存资源被创建一次,释放多次。
2. 如果需要复制,应该谨慎考虑。
重新定义复制构造函数和赋值操作符是必须的。怎么写它们是一个问题,具体的方案依赖于实际的需要,可以使用深拷贝,也可以使用类似于 shared_ptr 的引用计数机制,或者传递所有权。
总结一下:
1. 使用 RAII 能够将非内存资源的生命周期管理转为内存资源生命周期的管理,使得我们能够使用管理内存资源的手段来管理非内存资源,例如 auto_ptr,shared_ptr。
2. 维护 invariant 能够简化编程,使的代码简洁优雅。RAII 设计方式维护了这么一条 invariant:对象存在则资源有效。除此之外,我们还可以使用异常机制来维护另外一条 invariant:函数要么执行成功得到正确的结果,要么抛出异常。对此条,这里就不做任何阐述了。
3. 使用 RAII 时,应该警惕复制行为。
- ››RAII
更多精彩
赞助商链接