在C ++不好的做法中使用assert()?
我倾向于为我的C ++代码添加大量断言,以便在不影响发布版本性能的情况下进行debugging。 现在, assert
是一个纯粹的Cmacros,没有考虑C ++机制。
另一方面,C ++定义了std::logic_error
,它是在程序逻辑(因此名称)出现错误的情况下抛出的。 抛出一个实例可能只是完美的,更多的C ++ ish替代assert
。
问题是, assert
和abort
都立即终止程序而不调用析构函数,因此跳过清理,而手动抛出exception增加了不必要的运行成本。 解决这个问题的一个办法是创build一个自己的断言macrosSAFE_ASSERT
,它的作用就像C对应的一样,但是在失败的时候抛出一个exception。
我可以想到关于这个问题的三点意见:
- 坚持C的断言。 由于程序立即终止,修改是否正确展开并不重要。 另外,在C ++中使用
#define
也是一样糟糕。 - 抛出一个exception,并在main()中捕获它 。 允许代码在程序的任何状态下跳过析构函数都是不好的做法,必须不惜一切代价来避免,所以调用terminate()。 如果抛出exception,则必须被捕获。
- 抛出一个exception,让它终止程序。 终止程序的exception是可以的,并且由于
NDEBUG
,这在发布版本中不会发生。 捕捉是不必要的,并将内部代码的实现细节公开给main()
。
这个问题有一个明确的答案吗? 任何专业的参考?
编辑:跳过析构函数当然是没有不确定的行为。
断言在C ++代码中是完全合适的。 exception和其他error handling机制并不是与断言相同的东西。
error handling适用于有可能恢复或向用户报告错误的情况。 例如,如果尝试读取input文件时出现错误,则可能需要对此进行操作。 错误可能是由错误引起的,但也可能是给定input的合适输出。
断言是指在检查API时,检查是否符合API的要求,或者检查开发人员相信他是否通过构build保证的事情。 例如,如果一个algorithm需要sorting的input,你通常不会检查,但你可能有一个断言来检查它,以便debugging构build标志这种错误。 断言应该总是指示一个不正确的操作程序。
如果你正在编写一个不清洁的关机会导致问题的程序,那么你可能要避免断言。 未定义的行为严格地用C ++语言来说,在这里没有资格成为这样一个问题,因为触发一个断言可能已经是未定义行为的结果,或者违反了可能阻止某些清理工作正常工作的其他一些要求。
同样,如果你用exception来实现断言,那么它可能会被抓住和“处理”,即使这与断言的目的相矛盾。
-
断言是为了debugging 。 您提供的代码的用户不应该看到它们。 如果一个断言被击中,你的代码需要被修复。
-
例外情况是特殊情况 。 如果遇到了,用户将无法做到自己想做的事情,但可能可以在其他地方恢复。
-
error handling是针对正常的程序stream程的。 例如,如果您提示用户input一个数字并得到一些不可分的东西,这是正常的 ,因为用户input不在您的控制之下,您必须始终处理所有可能的情况。 (例如循环,直到你有一个有效的input,并在中间说“对不起,再试一次”)。
断言可以用来validation内部实现的不variables,比如执行一些方法之前或之后的内部状态,等等。如果断言失败了,这实际上意味着程序的逻辑被破坏,你不能从中恢复。 在这种情况下,你所能做的最好的事情就是尽可能快地中断,而不会传递给用户。 断言(至less在Linux上)真正好的是核心转储是由于进程终止而产生的,因此你可以很容易地调查堆栈跟踪和variables。 理解逻辑故障比exception消息更有用。
由于allorting()不会运行析构函数,所以不是未定义的行为!
如果是这样,那么调用std::terminate()
也是未定义的行为,那么提供它会有什么意义呢?
assert()
在C ++中与C中一样有用。断言不是用于error handling,而是用于立即中止程序。
恕我直言,断言是检查条件,如果违反,使所有其他的废话。 因此,你不能从中恢复,或者说,恢复是无关紧要的。
我将他们分为两类:
- 开发者罪(例如返回负值的概率函数):
float probability(){return -1.0; }
断言(概率()> 0.0)
- 机器坏了(例如运行你的程序的机器是非常错误的):
int x = 1;
assert(x> 0);
这些都是微不足道的例子,但离现实还不太远。 例如,考虑使用向量返回负指数的朴素algorithm。 或者定制硬件中的embedded式程序。 或者是因为狗屎发生 。
如果有这样的开发错误,你不应该有任何恢复或error handling机制实施的信心。 这同样适用于硬件错误。