何时应该使用assert()?

13

在开发一个有许多开发人员的大型C++编程项目中,我们遇到了assert()在代码中被不适当使用的问题,导致在确实出现断言的情况下产品崩溃,从而导致质量问题。

问题是什么是适当使用assert()的好原则? 何时使用assert()是合适的,何时不是? 是否有一系列标准,每个断言都必须满足才能合法? 我们如何鼓励正确地使用assert()?

首先,我认为assert()只应用于记录一种被认为不可能到达的条件,并且违反编程假设时应在运行时将其标识为assert()失败。

大家对此有更好的建议吗?你使用assert()的经验是什么?


4
当你知道某个条件必须成立才能被认为是“好”的代码时,请使用assert。如果assert失败,则根据定义需要修复代码。 - Robert Harvey
1
@Robert:同意+1,但必须考虑如果断言触发导致程序崩溃,用户将会失去多少工作。当浏览器丢失一组打开的标签时很烦人,但通常不是灾难;如果一个文字处理软件因为断言而丢失了一天的工作,那就是灾难了。困难的部分在于(a)确定是否安全进行任何操作,以及(b)保持系统处于可以恢复的状态,以防出现问题。 - Jonathan Leffler
1
那些整天不保存工作的人,当出现错误时就会得到他们应得的惩罚。 - Nick Hodges
在发布代码中不应该存在断言,它们只应该在系统开发过程中的调试代码中使用。在发布代码中应该使用异常处理。 - dannyhut
4个回答

14

使用异常处理来自外部(方法或程序之外)的错误情况,如参数检查以及缺失/有问题的外部资源(如文件、连接或用户输入)。

使用断言指示内部缺陷,如编程错误、不应发生的条件,例如类/方法不变式和无效程序状态。


1

在编程中,你应该使用assert来检查所有不应该发生的情况:

  • 输入参数的前置条件
  • 中间计算结果
  • 对象状态的后置条件

但是,你应该只在调试版本或显式激活发布版本时包含这些asserts(而不是在发布给客户的版本中)。


1
如果不良的前提条件等来自完全在您控制下的代码,则失败断言是可以接受的。但是对于这样的情况怎么办:缺少/错误的dll、错误的注册表条目等等。 - seand

1

我使用断言来检查任何不想要的程序状态:

  • 函数前提条件
  • 有时我在每个API调用后插入它们到一个宏中:glDrawArray(); checkOpenGLError();--checkOpenGLError()如果打开,将调用getGLError()
  • 数据结构完整性:assert(something == null);
  • 有时GDB会对我撒谎(iOS SDK 3.2)。我使用断言来证明它。

请注意,“不想要的程序状态”不包括在运行时自然发生的错误,例如由于权限或硬盘故障而无法打开用户选择的文件。在这些情况下,使用断言是不明智的。


0
现在很多代码都有很多外部依赖和连接。我不太喜欢用传统的断言,更偏爱使用异常。我觉得不能假设"这是不可能发生的",在非调试版本中可以安全地移除检查。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接