2012-08-02 55 views
3

为什么这是一种常见的做法,让assert宏只在调试配置中才有用?如果它存在测试不变量和检测编码错误,那么继续前进并在生产软件中做同样的繁荣是不是更容易?为什么断言宏仅用于调试版本

我有一些S60背景,并存在__ASSERT_ALWAYS__ASSERT_DEBUG,其中后者相当于assert

回答

5

检查断言成本。您可能不想在最终产品中存在额外的操作。如果断言总是在起作用,那么人们会开始使用它们来减少“不杀性能”。并相信我,有一个很多人谁认为额外的检查性能杀并会避免它。这些人实际上不得不使用断言更多!

更重要的原因是,如果失败,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 

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

实际上,您会随时获得软件的更新,他们声称他们已经修复了错误。其中的一些,确实是assert会发现的错误。然而,作为最终用户的你没有任何问题,并且真的很开心你不会因为那些assert而被打断,是不是?

+0

阶段1:启动车,阶段2:检查没有人在路上,阶段3:开车! - 所以如果我们跳过第二阶段,没问题? ;-)我明白你说的是什么,但总的来说,不管断言失败后继续是不是个好主意。 – Roddy 2012-08-02 15:08:53

+1

@roddy,我认为我们对于应该声称的内容有不同的看法。例如,'malloc'的输出不是我会断言的,但是确保我在AVL树上的左旋操作不会使树不平衡是我会用'assert'做的事情。不同之处在于第一个是应该处理的错误,否则就会发生不好的事情,第二个错误会造成性能问题。 – Shahbaz 2012-08-02 15:15:04

+0

我同意 - 您的AVL树是一个很好的例子,因为验证余额可能是一个相对较慢的操作。我宁愿看到malloc调用上的assert()比根本没有检查(尽管大多数应用程序没有处理malloc失败的有用方法)。当然,在C++'new'中,失败会抛出... – Roddy 2012-08-02 15:23:06

9

断言是应该永远不会发生的东西,即如果它确实比你的代码中有一个需要修复的错误。发布是“假定”没有错误的构建,并且为用户断言与断言一起杀死应用程序与其他任何错误行为一样糟糕。

+0

听起来很好,简单的回答 – 2012-08-02 13:20:07

+1

应用程序是死的任何方式。但没有断言,开发人员没有有用的方法来调试它。快速失败... – Roddy 2012-08-02 13:29:48

+0

@roddy,快速失败,但不在用户面前;) – Shahbaz 2012-08-02 13:31:30

0

assert有效,除非您明确关闭它。有(通常)没有 的理由关闭它,即使在“发布”版本中,我发布的大多数 已发布的代码都有assert活动。

关闭它的主要原因是性能。在这种情况下,你 关闭它非常局部,在函数里的表现 关键的,喜欢的东西:

#ifdef TURNOFFCRITICALASSERTS 
#define NDEBUG 
#include <assert.h> 
#endif 

// Function with critical code here... 

#undef NDEBUG 
#include <assert.h> 

这是C标准委员会设计assert的方式来使用。 通常,您不应该在本地定义NDEBUG,像这样。

3

我认为这是一种文化的东西。赞成在生产代码中删除这种检查的参数如下所示:

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

如下

  • 你发货,你测试的确切代码对运行参数。
  • 在现场调试报告的问题变得更加容易
  • 不管你想怎么想,你的代码运WILL有错误
  • 业绩和规模效应通常是最小的。
  • 如果程序处于非期望状态,尝试继续时可能会更快。

就我个人而言,我发布的软件完全按照测试,断言和所有软件构建。但是,在很大程度上取决于你的客户群,以及如何你希望计划发布...

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

但是当你部署软件向客户介绍什么?我们不要 想要应用程序崩溃,只是因为 配置文件中存在拼写错误。对此恐惧的一种反应是禁用该领域的断言 。

不要那样做!请记住, 客户网站发生的错误通过了您的测试过程。你可能 有麻烦重现它。这些错误是最难找到的,并且解释问题的恰当地断言可以为您节省数天的时间。其他

一两件事 - 在C++中,使用BOOST_ASSERT你可以将它扔在断言失败,这使得操作和更加有用断言失败可能恢复的异常。我们将此与MadExcept结合使用,以便该字段中的任何断言失败都可以轻松地由用户发布到我们的错误跟踪器中,并提供完整的调用堆栈,截图,whathaveyou。

+0

不幸的是,在一个资本主义鲨鱼的严酷世界中,几乎没有可重复的错误值得付出努力 – 2012-08-02 13:45:20

+0

@RomanSaveljev - 我不同意:一个bug的商业影响可能与复制的容易程度完全无关。 – Roddy 2012-08-02 15:03:35