为什么这是一种常见的做法,让assert
宏只在调试配置中才有用?如果它存在测试不变量和检测编码错误,那么继续前进并在生产软件中做同样的繁荣是不是更容易?为什么断言宏仅用于调试版本
我有一些S60背景,并存在__ASSERT_ALWAYS
和__ASSERT_DEBUG
,其中后者相当于assert
。
为什么这是一种常见的做法,让assert
宏只在调试配置中才有用?如果它存在测试不变量和检测编码错误,那么继续前进并在生产软件中做同样的繁荣是不是更容易?为什么断言宏仅用于调试版本
我有一些S60背景,并存在__ASSERT_ALWAYS
和__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
而被打断,是不是?
assert
有效,除非您明确关闭它。有(通常)没有 的理由关闭它,即使在“发布”版本中,我发布的大多数 已发布的代码都有assert
活动。
关闭它的主要原因是性能。在这种情况下,你 关闭它非常局部,在函数里的表现 关键的,喜欢的东西:
#ifdef TURNOFFCRITICALASSERTS
#define NDEBUG
#include <assert.h>
#endif
// Function with critical code here...
#undef NDEBUG
#include <assert.h>
这是C标准委员会设计assert
的方式来使用。 通常,您不应该在本地定义NDEBUG
,像这样。
我认为这是一种文化的东西。赞成在生产代码中删除这种检查的参数如下所示:
如下
就我个人而言,我发布的软件完全按照测试,断言和所有软件构建。但是,在很大程度上取决于你的客户群,以及如何你希望计划发布...
这篇文章值得一读: - http://www.martinfowler.com/ieeeSoftware/failFast.pdf
但是当你部署软件向客户介绍什么?我们不要 想要应用程序崩溃,只是因为 配置文件中存在拼写错误。对此恐惧的一种反应是禁用该领域的断言 。
不要那样做!请记住, 客户网站发生的错误通过了您的测试过程。你可能 有麻烦重现它。这些错误是最难找到的,并且解释问题的恰当地断言可以为您节省数天的时间。其他
一两件事 - 在C++中,使用BOOST_ASSERT你可以将它扔在断言失败,这使得操作和更加有用断言失败可能恢复的异常。我们将此与MadExcept结合使用,以便该字段中的任何断言失败都可以轻松地由用户发布到我们的错误跟踪器中,并提供完整的调用堆栈,截图,whathaveyou。
不幸的是,在一个资本主义鲨鱼的严酷世界中,几乎没有可重复的错误值得付出努力 – 2012-08-02 13:45:20
@RomanSaveljev - 我不同意:一个bug的商业影响可能与复制的容易程度完全无关。 – Roddy 2012-08-02 15:03:35
阶段1:启动车,阶段2:检查没有人在路上,阶段3:开车! - 所以如果我们跳过第二阶段,没问题? ;-)我明白你说的是什么,但总的来说,不管断言失败后继续是不是个好主意。 – Roddy 2012-08-02 15:08:53
@roddy,我认为我们对于应该声称的内容有不同的看法。例如,'malloc'的输出不是我会断言的,但是确保我在AVL树上的左旋操作不会使树不平衡是我会用'assert'做的事情。不同之处在于第一个是应该处理的错误,否则就会发生不好的事情,第二个错误会造成性能问题。 – Shahbaz 2012-08-02 15:15:04
我同意 - 您的AVL树是一个很好的例子,因为验证余额可能是一个相对较慢的操作。我宁愿看到malloc调用上的assert()比根本没有检查(尽管大多数应用程序没有处理malloc失败的有用方法)。当然,在C++'new'中,失败会抛出... – Roddy 2012-08-02 15:23:06