当前位置:  开发笔记 > 程序员 > 正文

什么时候断言应该留在生产代码中?

如何解决《什么时候断言应该留在生产代码中?》经验,为你挑选了7个好方法。

有一个讨论,在comp.lang.c超过回事++.关于缓和与否的断言,这在C++中默认情况下只在调试中存在的构建,应保持在生产代码或没有.

显然,每个项目都是独特的,所以在这里我的问题是没有这么多是否断言应该保持,但在这情况下,这是值得推荐的/不是一个好主意.

通过断言,我的意思是:

一个运行时检查,用于测试一个条件,当该条件为false时,会显示软件中的错误.

程序停止的机制(可能是在最小的清理工作之后).

我不一定在谈论C或C++.

我自己的观点是,如果你是程序员,但不拥有数据(大多数商业桌面应用程序就是这种情况),你应该保持它们,因为失败的断言显示了一个错误,你不应该去有bug,有可能破坏用户的数据.这会强制您在发货前进行强力测试,并使错误更加明显,从而更容易发现并修复.

你有什么看法/经验?

干杯,

卡尔

在此查看相关问题


回应和更新

嘿格雷厄姆,

断言是错误的,纯粹而简单,因此应该像一个一样处理.由于应该在发布模式下处理错误,因此您不需要断言.

这就是为什么我在谈论断言时更喜欢"bug"这个词.它使事情更加清晰.对我来说,"错误"这个词太模糊了.丢失的文件是错误,而不是错误,程序应该处理它.试图取消引用空指针是一个错误,程序应该承认有些东西闻起来像坏奶酪.

因此,您应该使用断言来测试指针,但是存在具有正常错误处理代码的文件.


稍微偏离主题,但讨论中的一个重点.

作为一个单挑,如果你的断言在失败时闯入调试器,为什么不呢.但是有很多原因导致文件不存在,完全不受代码控制:读/写权限,磁盘已满,USB设备已拔下等等.由于您无法控制它,我觉得断言是不是处理这个问题的正确方法.

卡尔


托马斯,

是的,我有代码完成,并且必须说我非常不同意该特定建议.

假设您的自定义内存分配器搞砸了,并将一些仍然被其他对象使用的内存归零.我碰巧将这个对象定期解除引用的指针归零,并且其中一个不变量是该指针永远不为空,并且你有几个断言以确保它保持这种状态.如果指针突然为空,你会怎么做?你只是if()围绕它,希望它有效吗?

请记住,我们在这里讨论产品代码,因此不会破坏调试器并检查本地状态.这是用户机器上的一个真正的错误.

卡尔



1> MSalters..:

断言是不会过时的评论.他们记录了哪些理论状态是有意的,哪些状态不应该出现.如果代码被更改,因此状态允许更改,很快就会通知开发人员,并且需要更新断言.


@jkschneider:单元测试功能不如评论.
@jkschneider:单元测试用于测试程序代码范围内的事物.在代码在这些假设下继续处理之前,断言是为了确保代码所基于的假设在实际中是真实的.它们是"文档",在某种意义上说,如果结果不是这样,程序将中止,陈述假设,并表明假设没有成立.当然,您也可以在代码中阅读断言作为文档的文档.
这是最好的答案,因为它使断言与注释相关联,这是一种思考它们的有用方法。它们是从注释中进步出来的,因为它们在开发过程中一直经过机器测试,但首先应始终对人类读者有意义。就像注释一样,它们不应成为逻辑或最终执行的一部分。就像注释一样,您可以根据语言是编译还是解释,发布计划,混淆策略等将其保留或删除。我已经看到一种情况,其中注释实际上导致了错误,但是那是一个怪异的

2> Thomas Owens..:

请允许我引用Steve McConnell的Code Complete.关于断言的部分是8.2.

通常,您不希望用户在生产代码中看到断言消息; 断言主要用于开发和维护期间.断言通常在开发时编译到代码中,并从代码中编译生产.

但是,在同一部分的后面,给出了这样的建议:

对于高度健壮的代码,断言然后再处理错误.

我认为只要性能不是问题,请保留断言,但不要显示消息,让它写入日志文件.我认为这个建议也在Code Complete中,但我现在还没找到.


我认为Code Complete的第二个引用意味着你应该有断言 - 它将在生产代码中编译出来 - 你应该_also_有"if(!condition){AttemptGracefulRecovery();}",即don让违反程序不变量的程序崩溃.

3> David Cary..:

保留断言在生产代码中打开,除非您已经测量程序在关闭时运行得更快.

如果不值得衡量以证明它更有效率,那么就不值得牺牲性能赌博的清晰度." - Steve McConnell 1993

http://c2.com/cgi/wiki?ShipWithAssertionsOn


实际上,最糟糕的事情是当代码由于某些不是断言而崩溃时.如果代码肯定会在以后以100%的概率崩溃,那么断言必须绝对存在.如果你deref一个指针,那么你必须隐式断言它之前不是null.如果除以数字,则断言它不为零.取出断言,所有崩溃位置都是UNDOCUMENTED.真正的问题不是构建程序以让子系统崩溃并由监视程序重新启动.
`assert ref!= null;`不同于`if(ref == null)抛出新的IllegalArgumentException();`你不应该使用第一个可能为false的前置条件.你需要使用`assert`来表示那些*不能为假的东西.例如,`int i = -1*someNumber; i = i*i;`然后提醒人们'i`是正面的,`断言i> 0;`

4> MiguelMunoz..:

如果你甚至想在生产中留下断言,你可能会认为它们是错误的.断言的全部意义在于,您可以在生产中关闭它们,因为它们不是您解决方案的一部分.它们是一种开发工具,用于验证您的假设是否正确.但是当你投入生产时,你应该对你的假设充满信心.

也就是说,有一种情况我将在生产中转换断言:如果我们在生产中遇到可重现的错误,我们在测试环境中很难再现,那么在打开断言的情况下重现错误可能会有所帮助在生产中,看看它们是否提供了有用的信息.

一个更有趣的问题是:在测试阶段,何时关闭断言?


如果将空指针传递给fn,你将不可避免地崩溃; 没有明确处理它的选择.您可以通过某种方式优雅地处理条件(因为它可能来自外部世界的输入),或者您在带有断言的DOCUMENTED位置崩溃,而不是在沿途可能已损坏的随机位置崩溃.断言如何处理应该是每个模块的决定.也许你的看门狗重新启动进程,或者你为该模块擦除一块内存以将其重置为启动状态(软对象"rebo​​ot").
我认为断言永远不应该包含在生产代码中.断言不是错误,它们是为开发人员设计的.断言应该只存在于测试代码中.有一个应用程序崩溃是因为和断言失败不可接受和草率的开发.开发人员需要加倍努力才能优雅地处理错误.

5> Mike Nakis..:

断言永远不应该停留在生产代码中.如果某个特定的断言似乎在生产代码中有用,那么它不应该是一个断言; 它应该是运行时错误检查,即像这样编码的东西:if( condition != expected ) throw exception.

术语"断言"已经意味着"开发时,只检查其将不会在球场上进行."

如果你开始认为断言可能会进入现场,那么你将不可避免地开始制造其他危险的想法,比如想知道任何给定的断言是否真的值得做.没有不值得做出的断言.你永远不应该问自己"我应该断言这个吗?" 你应该只问自己"有什么我忘记断言的吗?"



6> Anders Sandv..:

除非分析显示断言导致性能问题,否则我说它们也应该保留在生产版本中.

但是,我认为这也要求您在某种程度上优雅地处理断言失败.例如,它们应该产生一般类型的对话框,可以选择(自动)向开发人员报告问题,而不仅仅是退出或崩溃程序.此外,您应该注意不要将断言用于您实际允许的条件,但可能不喜欢或考虑不需要的条件.这些条件应该由代码的其他部分处理.



7> Qwertie..:

在我的C++中,我定义了REQUIRE(x),它类似于assert(x),只是如果断言在发布版本中失败,它会抛出异常.

由于失败的断言表明存在错误,因此即使在发布版本中也应该认真对待它.当我的代码性能很重要时,我经常会将REQUIRE()用于更高级别的代码,并将assert()用于必须快速运行的低级代码.如果失败条件可能是由第三方编写的代码传入的数据引起的,或者文件损坏,我也使用REQUIRE而不是断言(最好我会设计代码专门在文件损坏的情况下表现良好,但我们并不总是有时间这样做.)

他们说你不应该向最终用户展示这些断言消息,因为他们不会理解它们.所以?最终用户可能会向您发送一封带有屏幕截图的电子邮件或错误消息的某些文本,这有助于您进行调试.如果用户只是说"它崩溃了",那么你修复它的能力就会降低.最好通过互联网自动发送断言失败消息给自己,但这只有在用户可以访问互联网并且您可以获得他们的许可的情况下才有效.

推荐阅读
sx-March23
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有