痛并快乐着(一)------------C++申请资源时注意种种

趁着有那么一点点时间,把过去学习C++容易遗忘和疏忽的地方记录下来,以备以后学习之用。(如有不妥之处,希望技术好友指明)
我们在程序设计时会反复碰到一个问题,既某种资源申请失败的时候我们应该怎么处理呢?比如我们fopen()一个文件或者在堆内new了一块内存,但是我们没有留心如果这个文件不存在或者我们已经用光了所有的自由存储,那么会发生什么样的事情呢?针对这种情况,下面提出两种不同风格的解决方案。
唤醒:请求某个调用程序纠正问题,然后继续执行。
终止:立即结束当前的计算并且返回某个调用程序。
好。对于前一种情况,一个调用程序必须首先准备好,以便帮助处理某段未知代码中出现的资源申请问题,后一种情况既一个调用程序必须准备好去应付某个资源申请失败以后的情况种种。就大部分情况来说,做到后者是大为简单的,这样也能够使系统保持在抽象层次之间的一种较好的隔离(降低了抽象层次之间的依赖性,加强了松耦合)。但是要求注意的是在采用终止策略的时候,并不是终止整个的应用程序,而只是其中的某一个个别的计算而已(终止:听技术牛人说它是一个传统的描述策略的术语,我们可以理解为表示从失败的计算返回到与之相关联的调用过程的错误处理器<可以重试那个失败的计算>,而它不是表示去试图修复那个坏情况并从检查出问题的那个点继续下去。
在C++里,唤醒模型由函数调用机制支持,而终止模型由异常处理机制支持。这两种情况下面我们用标准库operator new()的一个简单的实现及其使用阐述说明:
Void * operator new( size_t size )
{
For(;;)
{
If( void* p = malloc( size ) ) return p;  //如果p不等于NULL则返回内存块指针
If( 0 == _new_handler ) throw bad_alloc();  //如果没有处理函数,抛离
_new_handler();      //处理函数进行帮助处理
}
}
这里,我们借助于标准C库malloc()来进行实际的内存检索分配工作,operator new()可以以其他多种方式实现。简单阐述函数为:如果开辟内存成功,operator new()就返回指向该内存的指针。如果找不到,operator new()就会调用_new_handler,如果得到了该帮助函数的处理,并且该帮助函数可以找到更多的内存供malloc分配,那就正是我们想要得到的了。如果找不到的话也不会就此返回operator new(),同时又不会导致无穷循环。_new_handler()可能选择抛出一个异常,这样这个麻烦就留给了调用者去处理。
Void m_new_handler()
{
Int found_bytes_offset = find_some_memory();
If( found_bytes_offset < min_allocation ) throw bad_alloc();
}
基于此种情况,应该在某一个地方有另一个带有适当处理器的try块
Try
{
 //…
}
Catch( bad_alloc )
{
 //对资源耗尽这种情况的回应
}
在operator new()的实现中所用的_new_handler是一个指向函数的指针,这个指针可以由标准函数set_new_handler()维护。如果我们想用m_new_handler()作为_new_handler使用,就写set_new_handler(&m_new_handler);如果我们还想捕捉bad_alloc,可以如下编写:
Void t()
{
Void(*old_nh )() = set_new_handler(&m_new_handler);
Try
{
 //..
}
Catch( bad_alloc )
{
 //..
}
Catch(…)
{
 Set_new_handler(old_nh );
Throw;
}
Set_new_handler(old_nh );
}
这个_new_handler并没有将更多的程序信息从查处错误的地方传递到能够起帮助作用的函数。要传递更多信息的话也不是什么难事。但是如果从检查运行时出现错误的代码向帮助处理这个错误的函数传递的程序信息越多,这样这两段代码之间的依赖性也就越强,如此的话,如果对其中的一段代码的修改必然会引起对另一段代码的理解,甚至会引起对另一段代码的修改。所以说如果要保持程序中分离的代码互相隔离,我们应该尽可能的减少这种依赖性。与去调用由某一个函数提供的帮助例程相比,异常处理机制对这种隔离的支持度更好一些。
如果我们把这种资源分配组织在抽象层次中的话,就可以很好的避免一层依赖于调用它的另一层提供的帮助。感觉这是成功系统的发展方向。
要想抛离一个异常,就要存在一个能够抛出的对象。每个C++实现都要求保留足够的存储,在存储耗尽的情况下还能够抛离bad_alloc。但是这样,由于抛离其他对象而导致存储耗尽的情况也是可能发生的。 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值