IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

僵尸对象或 RAII

Solrex Shuffling 2011-05-25 13:41:04 累计浏览 3,530 次
本机暂存

    我最近在想这个问题,到底要不要在程序中使用异常?

    以前写的 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++ 程序,那么异常处理是不可或缺的。但在使用异常处理之前,必须得了解在哪里、怎样抛出和捕获异常,如果是团队合作,可能还需要有简单的操作指导手册,否则使用不当或者过量的异常也可能带来麻烦。

    我还在路上!

同分类推荐文章

  1. 科技爱好者周刊(第 401 期):如何赚到10亿美元 (2026-06-26 08:05:38)
  2. 如何做决策 - 从 Go 的一个 issue 说起 (2026-06-26 08:00:00)
  3. Seven Player:Windows上播放115网盘视频的增强工具 (2026-06-09 00:06:47)

查看更多 开发者 文章 →

建议继续学习

  1. Java开发岗位面试题归类汇总 (累计阅读 22,155)
  2. Linux内存点滴 用户进程内存空间 (累计阅读 13,228)
  3. Linux Used内存到底哪里去了? (累计阅读 11,866)
  4. 如何学好C++语言 (累计阅读 10,448)
  5. Emacs配置C/C++-mode的代码智能提示和自动补全 (累计阅读 10,411)
  6. colortail,让 tail 命令绚丽起来 (累计阅读 10,259)
  7. Linux操作系统的内存使用方法详细解析 (累计阅读 10,149)
  8. PHP的异常原理与实例说明 Fatal error: Uncaught exception (累计阅读 9,763)
  9. 在C++中实现foreach循环,比for_each更简洁! (累计阅读 9,499)
  10. 几个内存相关面试题(c/c++) (累计阅读 9,444)