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

时间:2012-08-02 13:09:52

标签: c++ c debugging assert

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

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

4 个答案:

答案 0 :(得分:11)

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

答案 1 :(得分: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

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

实际上,您会随时获得软件的更新,声称他们已经修复了错误。其中一些,确实是assert会遇到的错误。但是,作为最终用户,您没有遇到任何问题,并且因为assert而未被打断而感到高兴,不是吗?

答案 2 :(得分:5)

我认为这是一种文化事物。支持在生产代码中删除此类检查的论据如下:

  • 这会让您的代码运行得更慢。
  • 它使最终的可执行文件更大。
  • 您的代码一旦出货就不应该有错误。
  • 这将导致您的程序突然和暴力退出,可能会丢失数据。

反对运行的参数如下

  • 您正在发送您测试的完全代码。
  • 现场报告的调试问题变得更加容易
  • 无论您想要什么,您发送的代码有错误
  • 性能和尺寸效果通常很小。
  • 当您的程序处于不受欢迎的状态时,尝试继续运行可能比继续失败更快。

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

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

  

但是当您将软件部署到客户时呢?我们没有   希望应用程序崩溃只是因为有一个错字   配置文件。对这种恐惧的一种反应是禁用断言   在现场。

     

不要那样做!请记住,发生错误   客户的网站通过您的测试过程。你可能会   难以复制它。这些错误是最难找到的,并且   一个很好的断言解释这个问题可以节省你几天   努力。

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

答案 3 :(得分:1)

assert除非您明确将其关闭,否则无效。 (通常)没有 有理由关闭它,即使在“发布”版本中,以及大多数 已发布的已发布的代码已激活assert

关闭它的主要原因是性能。在这种情况下,你 在性能所在的函数中非常本地关闭它 关键,如:

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

//  Function with critical code here...

#undef NDEBUG
#include <assert.h>

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