僵尸对象或 RAII
我最近在想这个问题,到底要不要在程序中使用异常?
以前写的 C 代码比较多,即使写 C++,基本上也是把它当成 C with object 来用。对异常的了解偏少,使用更是极少。最近评审别人代码的时候遇到一个问题:如果构造函数中 new 失败了,会发生什么事情?
工程的代码一般提倡哪里出错在哪里处理,不能恢复的要返回错误码给调用者。在一般情况下,使用 new(std::no_throw) 保证 new 不抛出异常(否则结果是灾难性的),并且检查分配是否成功是可以实现这一点的。
遗憾的是构造函数没有返回值,我们不能返回构造失败。那么只有用迂回的办法,为类定义一个成员变量 bool inited。初始化为 false,只有在构造的工作都完成之后,才将它置为 true。如果一个对象的 inited 成员为 false,就意味着它构造过程中出了问题,不能被使用。这就是一个僵尸对象,“活死人”。
看,我们成功地规避了使用异常。但是慢着,不是只有 bad_alloc 这一个异常啊!还有 bad_cast、runtime_error、logic_error,还有:
$ grep class /usr/include/c++/4.5/stdexcept // Standard exception classes -*- C++ -*- // ISO C++ 19.1 Exception classes * program runs (e.g., violations of class invariants). * @brief One of two subclasses of exception. class logic_error : public exception class domain_error : public logic_error class invalid_argument : public logic_error class length_error : public logic_error class out_of_range : public logic_error * @brief One of two subclasses of exception. class runtime_error : public exception class range_error : public runtime_error class overflow_error : public runtime_error class underflow_error : public runtime_error
天那,我未曾注意过标准库有那么多异常!那么如果在使用标准库时,不小心触发了什么异常,OMG!
这样看来,使用异常是很有必要的。但是,麻烦的问题又来了,一旦使用异常,函数的退出过程就变了。使用错误码有一个好处,就是你可以在函数返回前擦干净自己的屁股;但是使用异常呢?你既要保证对象能够自己擦屁股(RAII),还要保证函数能自己擦屁股(在正确的位置使用异常处理),这样才能在 stack unwinding 时不会导致内存泄露。
还有一个麻烦是,你要遵从约定――特别是对于一个程序库作者来说。如果约定出错时抛出异常,那么可以抛;如果约定出错时返回错误码,或者这个库可能被 C 调用,那么抛出异常就可能是灾难。
现在看来,如果想实现更健壮的 C++ 程序,那么异常处理是不可或缺的。但在使用异常处理之前,必须得了解在哪里、怎样抛出和捕获异常,如果是团队合作,可能还需要有简单的操作指导手册,否则使用不当或者过量的异常也可能带来麻烦。
我还在路上!
建议继续学习:
- PHP的异常原理与实例说明 Fatal error: Uncaught exception (阅读:8943)
- 是返回错误码,还是抛出异常?说说我的选择 (阅读:5950)
- Perl 异常处理之 autodie 和 Try::Tiny (阅读:2685)
- PHP程序员也要学会使用“异常” (阅读:2634)
- 异常的代价 (阅读:2514)
- PHP错误处理及异常处理 (阅读:2574)
- 深入理解PHP之异常机制 (阅读:2459)
- 我们什么时候应该使用异常? (阅读:2413)
- Java处理InterruptedException异常小结 (阅读:1893)
- Swift错误和异常处理 (阅读:948)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:Solrex Yang 来源: Solrex Shuffling
- 标签: RAII 僵尸对象 异常
- 发布时间:2011-05-25 13:41:04
- [70] Twitter/微博客的学习摘要
- [66] 如何拿下简短的域名
- [65] IOS安全–浅谈关于IOS加固的几种方法
- [64] find命令的一点注意事项
- [63] android 开发入门
- [63] Go Reflect 性能
- [61] 流程管理与用户研究
- [59] 图书馆的世界纪录
- [59] 读书笔记-壹百度:百度十年千倍的29条法则
- [59] Oracle MTS模式下 进程地址与会话信