为什么断言宏仅用于调试构建

Rom*_*jev 5 c c++ debugging assert

为什么assert宏只在调试配置中做一些有用的事情是一种常见的做法?如果它存在以测试不变量并检测编码错误,那么继续在生产软件中进行同样的大繁荣会不会更容易?

我有一些S60的背景和存在__ASSERT_ALWAYS__ASSERT_DEBUG,后者相当于assert.

yur*_*hek 11

断言是针对应该永远不会发生的事情,即如果它确实存在,则代码中存在需要修复的错误.版本是"假设"没有错误的版本,使用用户断言查杀应用程序与任何其他错误行为一样糟糕.

  • 两种方式的应用程序都失效。但是没有断言,开发人员就没有调试它的有用方法。快速失败... (2认同)
  • @roddy,快速失败,但不要当着用户的面;) (2认同)
  • @Shahbaz - 无论如何,你在用户面前失败了。最好尽早且可预测地失败,而不是努力假设您忽略的缓冲区溢出不会那么重要...... (2认同)

Sha*_*baz 7

检查断言成本.您可能不希望在最终产品中存在额外的操作.如果断言总是会起作用,那么人们就会开始使用它们而不是"不要杀死性能".并且相信我,有很多人认为额外的检查是性能杀戮并且会避免它.这些人实际上必须使用断言更多!

更重要的原因是assert,如果失败,将只是中止您的程序.对于最终用户而言,没有任何用处.如果您希望程序实际上以消息终止或执行有用的操作,则必须编写自己的断言.在这种情况下,您当然可以选择将其保持在发布模式.

最后,断言可以帮助您发现错误,特别是隐藏的错误,但在执行软件时,它们实际上可能不会发生.想象一下以下代码:

struct X
{
    // other stuff
    int stage;
};

X x;
... do some stuff
assert(x.stage == STAGE_2);
x.stage = STAGE_3; // go to next stage
... do more stuff
Run Code Online (Sandbox Code Playgroud)

在这样的例子中,你的逻辑说x应该在STAGE_2.如果不是,那就是一个bug.但是,如果您删除断言,修复x.stage并继续前进,则希望错误不是那么严重.在这种情况下,最终用户实际上可以继续工作而不会注意到这一点.如果你一直assert处于发布模式,你会强迫这个人退出一个没有任何明显效果的bug.

实际上,您会随时获得软件的更新,声称他们已经修复了错误.其中一些,确实是assert可能会遇到的错误.但是,你作为最终用户没有任何问题,实际上是幸福的,你是不是因为那些打断assertS,不是吗?

  • @roddy,我认为我们对于应该断言的内容有不同的想法。例如,我不会断言`malloc`的输出,但是要确保我对AVL树的左旋转操作不会使树不平衡,这是我要声明的。区别在于,第一个是应该处理的错误,否则会发生不好的事情,第二个是最坏的性能问题。 (3认同)

Rod*_*ddy 5

我认为这是文化的事情。支持删除生产代码中这种检查的参数如下:

  • 这会使您的代码运行速度变慢。
  • 它使最终的可执行文件更大。
  • 一旦发布,您的代码就不应有错误。
  • 这将导致您的程序突然猛烈退出,并可能丢失数据。

反对run的论据如下

  • 您将交付测试的确切代码。
  • 现场报告的调试问题变得更加容易
  • 不管你想怎么想,你船的代码WILL有错误
  • 性能和尺寸影响通常很小。
  • 当程序处于不希望的状态时,快速失败比尝试继续运行更可取。

就我个人而言,我提供的软件完全按照经过测试,声明和所有的方式构建。但是,很大程度上取决于您的客户群以及您希望如何安排发布...

这篇文章值得一读:-http: //www.martinfowler.com/ieeeSoftware/failFast.pdf

但是,当您将软件部署给客户时又如何呢?我们不希望仅由于配置文件中有错字而导致应用程序崩溃。对这种恐惧的一种反应是禁用现场断言。

不要那样做!请记住,在客户现场发生的错误是通过测试过程完成的。您可能很难复制它。这些错误是最难发现的,并且适当放置的断言来解释问题可以节省您数日的工作。

另一件事-在C ++中,可以使用BOOST_ASSERT将其设置为在断言失败时引发异常,这使处理断言并可能从断言失败中恢复更加有用。我们将其与MadExcept结合使用,以便用户可以轻松地将字段中的任何断言故障发布到我们的错误跟踪器中,并提供完整的调用堆栈,屏幕截图以及您拥有的一切。