ScopeGuard:编写Exception-Safe代码

本文介绍了一种改进C++异常处理的方法,通过ScopeGuard机制避免try/catch带来的代码复杂性,利用C++特性确保资源正确释放。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在开发C++程序时经常需要编写异常处理代码,异常处理机制的优点是可以让低层的错误沿着调用堆栈往上传递直至其被捕获并被处理,其缺点在于try/catch代码块的引用导致代码结构复杂,处理流程变得不清晰,代码的维护成本也增加了,Generic<Programming>: Change the Way You Write Exception-Safe Code Forever 介绍了一种巧妙的方式来摆脱try/catch的禁锢,让代码读更加简洁、优雅。

 

本文不再赘述原文中的解决方法,重点介绍一下其实现机制。


  
1 /* *
2 * ScopeGuardImplBase基类负责管理dismissed_标记,dismissed_的值决定了派生类析构时是否需要调用处理函数进行清理
3   */
4   class ScopeGuardImplBase {
5 public :
6 void Dismiss() const throw () {
7 dismissed_ = true ;
8 }
9
10 protected :
11 ScopeGuardImplBase() : dismissed_( false ) {}
12
13 ScopeGuardImplBase( const ScopeGuardImplBase & other) : dismissed_(other.dismissed_) {
14 other.Dismiss();
15 }
16
17 // 没有使用虚析构函数
18 ~ ScopeGuardImplBase() {}
19
20 mutable bool dismissed_;
21
22 private :
23 // 不允许赋值操作
24 ScopeGuardImplBase & operator = ( const ScopeGuardImplBase & );
25 };
26
27
28 /* *
29 * ScopeGuardImpl1派生类实现参数个数为1的处理函数调用
30 */
31 template < typename Fun, typename Parm >
32 class ScopeGuardImpl1 : public ScopeGuardImplBase {
33 public :
34 ScopeGuardImpl1( const Fun & fun, const Parm & parm)
35 : fun_(fun), parm_(parm)
36 {}
37
38 // 对象析构时自动调用处理函数
39 ~ ScopeGuardImpl1() {
40 if ( ! dismissed_) fun_(parm_);
41 }
42
43 private :
44 Fun fun_;
45 const Parm parm_;
46 };
47
48 /* *
49 * ScopeGuardImpl1的helper函数
50 */
51 template < typename Fun, typename Parm >
52 ScopeGuardImpl1 < Fun, Parm > MakeGuard( const Fun & fun, const Parm & parm) {
53 return ScopeGuardImpl1 < Fun, Parm > (fun, parm);
54 }
55
56 /* *
57 * ScopeGuard为ScopeGuardImplBase的常引用类型
58 */
59 typedef const ScopeGuardImplBase & ScopeGuard;

从上面的代码中可以看出基类ScopeGuardImplBase并不是通过虚析构函数来实现多态,而是通过将ScopeGuard定义为ScopeGuardImplBase的常引用类型,其技巧是依据C++标准:使用临时变量来初始化引用,该临时变量将一直存在直至引用的生命周期结束

 

下面通过一个例子来说明:


  
FILE * topSecret = std::fopen( " cia.txt " );
ScopeGuard closeIt
= MakeGuard(std::fclose, topSecret);
MakeGuard函数生成了一个类型为“ScopeGuardImpl1<int (&)(FILE*), FILE*>”的临时变量,并赋值给常引用closeIt, 当closeIt生命周期结束时其实际类型的析构函数会被执行,从而调用std::fclose(topSecret)

 

上面的代码中只提供了接受1个参数的ScopeGuardImpl1对象类型,只要依葫芦画瓢就很容易实现接受0个、2个或者更多个参数的派生类型(ScopeGuardImpl0, ScopeGuardImpl2...);同时还需要重载helper函数MakeGuard来支持不同的参数个数实现版本。

 

原文中还提供了使用对象成员函数作为处理函数的版本,实现原理和上面普通函数版本一致。

 

boot版本

熟悉boost的同学会发现借助boost::shared_ptrboost::bind就可实现这个ScopeGuard工具,详见:Using shared_ptr to execute code on block exit

 

转载于:https://www.cnblogs.com/edwardlost/archive/2010/12/02/1894318.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值