为什么让assert
宏只在调试配置中做一些有用的事情是一种常见的做法?如果存在测试不变量和检测编码错误的存在,那么继续在生产软件中实现同样的大繁荣不是更容易吗?
我有一些 S60 背景,存在__ASSERT_ALWAYS
and __ASSERT_DEBUG
,后者相当于assert
.
断言是为那些不应该发生的事情而制作的,即如果它发生了,那么你的代码中有一个你需要修复的错误。发布是“假定”没有错误的构建,并且使用断言为用户杀死应用程序与任何其他错误行为一样糟糕。
检查断言成本。您可能不希望在最终产品中存在额外的操作。如果断言总是有效,那么人们就会开始减少使用它们“以不影响性能”。相信我,有很多人认为额外的检查会扼杀性能并且会避免它。这些人实际上必须更多地使用断言!
一个更重要的原因是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
s 而被打断,不是吗?
我认为这是一个文化问题。支持在生产代码中删除这种检查的论点如下:
反对 run 的论据如下
就个人而言,我发布的软件完全按照它的测试、断言和所有方式构建。但是,很大程度上取决于您的客户群以及您希望如何安排发布...
这篇文章值得一读:- http://www.martinfowler.com/ieeeSoftware/failFast.pdf
但是当您将软件部署给客户时呢?我们不希望应用程序因为配置文件中的错误而崩溃。对这种恐惧的一种反应是禁用该领域的断言。
不要那样做!请记住,客户站点上发生的错误通过了您的测试过程。你可能很难复制它。这些错误是最难发现的,而一个恰当的断言来解释问题可以为您节省数天的精力。
另一件事 - 在 C++ 中,使用BOOST_ASSERT您可以将其设置为在断言失败时抛出异常,这使得处理断言失败并可能从断言失败中恢复更加有用。我们将它与MadExcept结合使用,以便用户可以轻松地将字段中的任何断言失败发布到我们的错误跟踪器中,并提供完整的调用堆栈、屏幕截图、whathaveyou。
assert
除非您明确将其关闭,否则可以正常工作。(通常)没有理由将其关闭,即使在“发布”版本中也是如此,而且我交付的大多数已发布代码都assert
处于活动状态。
关闭它的主要原因是性能。在这种情况下,您可以在性能至关重要的函数中非常局部地关闭它,例如:
#ifdef TURNOFFCRITICALASSERTS
#define NDEBUG
#include <assert.h>
#endif
// Function with critical code here...
#undef NDEBUG
#include <assert.h>
这是 C 标准委员会设计assert
使用的方式。一般来说,你不应该NDEBUG
像这样在本地定义 except 。