题
断言是用来检查一个条件是否被满足(前提条件,后置条件,不变量)和帮助程序员发现调试阶段期间的孔。
例如,
void f(int *p)
{
assert(p);
p->do();
}
我的问题是我们需要假设的条件不能在释放模式得到满足,并相应处理的情况下?
void f(int *p)
{
assert(p);
if (p)
{
p->do();
}
}
毕竟,断言装置,它测试条件绝不应该假。但是,如果,如果我们不检查它,它失败了,程序崩溃。听起来像一个两难境地。你们如何处理呢?
解决方案
如果断言失败,请该方案应崩溃强>
断言故障装置程序员在他们的是多么可能的是,程序流程进行理解制成一个基本的错误。这是一个发展援助,而不是一个生产援助。在生产中,人们可能会处理的例外的,因为他们“可能”发生的,而断言应该“从来没有”失败。
如果您在说,营地是“哦,但如果断言在生产失败呢?我需要抓住他们!”那么你就错过了点。问问自己,在这种情况下,你为什么不只是抛出一个异常(或以其他方式处理错误)?
一般来说,断言的是的不的只是一个速记“如果条件不满足,抛出异常”(当然,有时这是操作语义,但它不是指称语义)。相反,断言故障装置的应用是在的显影剂不相信的状态为偶数可能 即可。难道你真的想要的代码继续在这种情况下执行?显然,(我想说)的没有的。
其他提示
防御性编程始终是最好。你应该总是假设,尽管所有的测试,你的应用程序将错误发货。因此,它是在添加NULL检查中情况下,您可以避开一个NULL指针尊重,只是继续前进的最佳利益。
然而,在有些情况下根本没有简单的方法来避免碰撞,并且在这些情况下,保持断言是唯一的期间开发周期检测所述问题的一种方法。
很重要的一点,虽然 - 断言也经常用来检测你的数据的完整性的重大问题。如果继续过去那些断言,你可能会冒险破坏数据。在这种情况下,它可能是更好的崩溃,而不是破坏你的数据。 (显然,任何种类的崩溃处理的至少带来了一个错误描述一个合理的UI将是优选的)。
严格地说,第二代码有冗余度。
void f(int *p)
{
assert(p);
if (p) // Beats the purpose of assertion
{
p->do();
}
}
已发生断言装置错误。东西是出乎意料/未处理。在上面的代码中,或者
1)你正在正确地处理其中p是零的情况。 (不是通过调用P->做()) - 这理应是正确的/预期的事情。但是,则断言是一种假警报
2)。另一方面,如果通过不调用P->做的(),事情会在代码或输出出错(也许还),然后断言是正确的,但应该是没有任何意义继续反正。
在上面的代码中,程序员正在加倍努力办案其是错误的反正。
这是说,有些人喜欢对待声称为的出了问题,还是让我们看看我们是否仍然可以得到正确的输出的。 IMO,即坏策略和错误修正期间创建混淆。
断言调试代码,不工作的代码。不要用它们来捕捉输入错误。
断言用于捕获的错误在测试。该理论认为,你测试不够好,知道它会工作,一旦你已经发布了。
如果有,该情况可能在现实生活中出现的操作,不依赖于任何说法的可能性 - 使用异常或某些其他错误机制
断言是你提到调试是有用的。他们不应该使之成为生产代码(如编译,它的确定包起来当然的#ifdefs)
如果你正在运行到一个问题,这是你无法控制的整顿和你所需要的支票在你的产品代码我会做这样的事情:
void f(int *p)
{
if (!p)
{
do_error("FATAL, P is null.");
}
p->do();
}
其中do_error是记录错误并干净地退出的功能。
我说,让他们在一个发布版本。还有势必要在任何构建错误。在你的产品的手段断言,当您收到问题报告从一个uwer可以更方便地查明问题。
不要把很多精力在处理异常。肯定只是让你可以得到完整的例外,includigg堆栈跟踪的保持。这适用于在特定发布版本。
由于很多人评论将断言在释放模式:
在我工作的,效率是非常重要的(有时,在大数据集的执行需要几十个小时到几天才能完成)。因此,我们有一个断言仅在调试代码(QA等过程中运行)的特殊宏。举个例子,对于环内的断言绝对是一个开销,你可能希望避免它发布代码。毕竟,如果所有IZ井,断言不应该失败。
其中释放代码断言一个实例是好是 - 如果逻辑是不应该在所有命中的代码的特定分支。在这种情况下,断言(0)是细[因而任何种类的assert(0)总是可以在释放代码左]。