有一个讨论,在comp.lang.c超过回事++.关于缓和与否的断言,这在C++中默认情况下只在调试中存在的构建,应保持在生产代码或没有.
显然,每个项目都是独特的,所以在这里我的问题是没有这么多是否断言应该保持,但在这情况下,这是值得推荐的/不是一个好主意.
通过断言,我的意思是:
一个运行时检查,用于测试一个条件,当该条件为false时,会显示软件中的错误.
程序停止的机制(可能是在最小的清理工作之后).
我不一定在谈论C或C++.
我自己的观点是,如果你是程序员,但不拥有数据(大多数商业桌面应用程序就是这种情况),你应该保持它们,因为失败的断言显示了一个错误,你不应该去有bug,有可能破坏用户的数据.这会强制您在发货前进行强力测试,并使错误更加明显,从而更容易发现并修复.
你有什么看法/经验?
干杯,
卡尔
在此查看相关问题
回应和更新
嘿格雷厄姆,
断言是错误的,纯粹而简单,因此应该像一个一样处理.由于应该在发布模式下处理错误,因此您不需要断言.
这就是为什么我在谈论断言时更喜欢"bug"这个词.它使事情更加清晰.对我来说,"错误"这个词太模糊了.丢失的文件是错误,而不是错误,程序应该处理它.试图取消引用空指针是一个错误,程序应该承认有些东西闻起来像坏奶酪.
因此,您应该使用断言来测试指针,但是存在具有正常错误处理代码的文件.
稍微偏离主题,但讨论中的一个重点.
作为一个单挑,如果你的断言在失败时闯入调试器,为什么不呢.但是有很多原因导致文件不存在,完全不受代码控制:读/写权限,磁盘已满,USB设备已拔下等等.由于您无法控制它,我觉得断言是不是处理这个问题的正确方法.
卡尔
托马斯,
是的,我有代码完成,并且必须说我非常不同意该特定建议.
假设您的自定义内存分配器搞砸了,并将一些仍然被其他对象使用的内存归零.我碰巧将这个对象定期解除引用的指针归零,并且其中一个不变量是该指针永远不为空,并且你有几个断言以确保它保持这种状态.如果指针突然为空,你会怎么做?你只是if()围绕它,希望它有效吗?
请记住,我们在这里讨论产品代码,因此不会破坏调试器并检查本地状态.这是用户机器上的一个真正的错误.
卡尔
断言是不会过时的评论.他们记录了哪些理论状态是有意的,哪些状态不应该出现.如果代码被更改,因此状态允许更改,很快就会通知开发人员,并且需要更新断言.
请允许我引用Steve McConnell的Code Complete.关于断言的部分是8.2.
通常,您不希望用户在生产代码中看到断言消息; 断言主要用于开发和维护期间.断言通常在开发时编译到代码中,并从代码中编译生产.
但是,在同一部分的后面,给出了这样的建议:
对于高度健壮的代码,断言然后再处理错误.
我认为只要性能不是问题,请保留断言,但不要显示消息,让它写入日志文件.我认为这个建议也在Code Complete中,但我现在还没找到.
保留断言在生产代码中打开,除非您已经测量程序在关闭时运行得更快.
如果不值得衡量以证明它更有效率,那么就不值得牺牲性能赌博的清晰度." - Steve McConnell 1993
http://c2.com/cgi/wiki?ShipWithAssertionsOn
如果你甚至想在生产中留下断言,你可能会认为它们是错误的.断言的全部意义在于,您可以在生产中关闭它们,因为它们不是您解决方案的一部分.它们是一种开发工具,用于验证您的假设是否正确.但是当你投入生产时,你应该对你的假设充满信心.
也就是说,有一种情况我将在生产中转换断言:如果我们在生产中遇到可重现的错误,我们在测试环境中很难再现,那么在打开断言的情况下重现错误可能会有所帮助在生产中,看看它们是否提供了有用的信息.
一个更有趣的问题是:在测试阶段,何时关闭断言?
断言永远不应该停留在生产代码中.如果某个特定的断言似乎在生产代码中有用,那么它不应该是一个断言; 它应该是运行时错误检查,即像这样编码的东西:if( condition != expected ) throw exception
.
术语"断言"已经意味着"开发时,只检查其将不会在球场上进行."
如果你开始认为断言可能会进入现场,那么你将不可避免地开始制造其他危险的想法,比如想知道任何给定的断言是否真的值得做.没有不值得做出的断言.你永远不应该问自己"我应该断言这个吗?" 你应该只问自己"有什么我忘记断言的吗?"
除非分析显示断言导致性能问题,否则我说它们也应该保留在生产版本中.
但是,我认为这也要求您在某种程度上优雅地处理断言失败.例如,它们应该产生一般类型的对话框,可以选择(自动)向开发人员报告问题,而不仅仅是退出或崩溃程序.此外,您应该注意不要将断言用于您实际允许的条件,但可能不喜欢或考虑不需要的条件.这些条件应该由代码的其他部分处理.
在我的C++中,我定义了REQUIRE(x),它类似于assert(x),只是如果断言在发布版本中失败,它会抛出异常.
由于失败的断言表明存在错误,因此即使在发布版本中也应该认真对待它.当我的代码性能很重要时,我经常会将REQUIRE()用于更高级别的代码,并将assert()用于必须快速运行的低级代码.如果失败条件可能是由第三方编写的代码传入的数据引起的,或者文件损坏,我也使用REQUIRE而不是断言(最好我会设计代码专门在文件损坏的情况下表现良好,但我们并不总是有时间这样做.)
他们说你不应该向最终用户展示这些断言消息,因为他们不会理解它们.所以?最终用户可能会向您发送一封带有屏幕截图的电子邮件或错误消息的某些文本,这有助于您进行调试.如果用户只是说"它崩溃了",那么你修复它的能力就会降低.最好通过互联网自动发送断言失败消息给自己,但这只有在用户可以访问互联网并且您可以获得他们的许可的情况下才有效.