断言何时应保留在生产代码中?
在comp.lang.c ++。moderated上正在进行一场讨论,讨论是否应将断言(应在C ++中默认情况下仅存在于调试版本中)保留在生产代码中。
显然,每个项目都是唯一的,所以我在这里的问题不是是否应该保留断言,而是在这种情况下,建议这样做/不是一个好主意。
断言是指:
- 一种运行时检查,用于测试条件,条件为false时,该条件表明软件中存在错误。
- 暂停程序的一种机制(可能是在清理工作最少之后)。
我不一定要谈论C或者C ++。
我个人的观点是,如果我们是程序员,但不拥有数据(大多数商业桌面应用程序就是这种情况),则应保留它们,因为断言失败会显示错误,并且我们不应该去带有错误,可能会损坏用户的数据。这迫使我们在发货之前进行严格的测试,并使错误更明显,从而更容易发现和修复。
看法/经验是什么?
干杯,
卡尔
在这里查看相关问题
回应和更新
嘿,格雷厄姆,
An assertion is error, pure and simple and therefore should be handled like one. Since an error should be handled in release mode then you don't really need assertions.
这就是为什么我在谈论断言时更喜欢" bug"一词的原因。它使事情变得更加清晰。对我来说,"错误"一词太含糊了。丢失的文件是一个错误,而不是错误,程序应该对其进行处理。尝试取消引用空指针是一个错误,程序应该承认有些东西闻起来像坏奶酪。
因此,我们应该使用断言测试指针,但是使用正常的错误处理代码来测试文件的存在。
话题不大,但在讨论中很重要。
请注意,如果断言失败,则断言会进入调试器,为什么不这样做。但是有很多原因导致文件不存在,这完全超出了代码的控制范围:读/写权限,磁盘已满,USB设备已拔出等。由于我们无法控制它,因此我认为是断言不是正确的处理方式。
卡尔
托马斯
是的,我有完整的代码,必须说我完全不同意该建议。
假设自定义内存分配器已拧紧,然后将仍由其他对象使用的大块内存清零。我碰巧将此对象定期取消引用的指针归零,其中一个不变之处是该指针永远不会为null,并且我们有几个断言来确保它保持这种状态。如果指针突然为空,该怎么办。我们只是围绕它if(),希望它能正常工作?
记住,我们在这里谈论产品代码,因此不会打扰调试器并检查本地状态。这是用户计算机上的真实错误。
卡尔
解决方案
回答
除非分析表明断言导致性能问题,否则我说它们也应保留在生产版本中。
但是,我认为这还要求我们一定程度地处理断言失败。例如,它们应该导致一种常规类型的对话框,并带有(自动)向开发人员报告问题的选项,而不仅仅是退出程序或者使程序崩溃。另外,我们应注意不要对确实允许但可能不喜欢或者认为不想要的条件使用断言。这些条件应由代码的其他部分处理。
回答
断言是错误,纯净而简单的断言,因此应像对待一个断言一样处理。
由于应该在发布模式下处理错误,因此我们实际上不需要断言。
我看到的断言的主要好处是有条件的中断,它们的设置比在VC窗口中进行钻取来设置需要1行代码的代码要容易得多。
回答
除了编译时间类型检查之外,我很少使用断言。我会使用异常而不是断言,因为大多数语言都是为处理它们而构建的。
我举一个例子
file = create-some-file(); _throwExceptionIf( file.exists() == false, "FILE DOES NOT EXIST");
反对
file = create-some-file(); ASSERT(file.exists());
应用程序将如何处理断言?我更喜欢处理致命错误的老式" try catch"方法。
回答
大多数时候,当我在Java中使用断言(assert关键字)时,我会在之后自动添加一些生产代码。根据情况,它可以是日志消息,异常……或者什么都没有。
根据我的说法,所有主张对开发版本至关重要,而不对生产发布至关重要。其中一些必须保留,而其他则必须丢弃。
回答
如果像对待其他任何错误一样处理它们,则不会出现任何问题。请记住,尽管与其他语言一样,使用C失败的断言只会退出程序,并且这通常不足以用于生产系统。
例如,有一些例外情况,PHP允许我们为断言失败创建自定义处理程序,以便我们可以显示自定义错误,进行详细的日志记录等,而不仅仅是退出。
回答
如果要保留它们,请用错误处理替换它们。没有什么比消失的程序更糟糕了。我认为将某些错误视为严重的bug并没有错,但是应该将它们定向到程序的一部分,该部分可以通过收集数据,记录日志并通知用户应用存在某些不良情况来处理这些错误,正在退出。
回答
请允许我引用史蒂夫·麦康奈尔的《代码完成》。关于断言的部分是8.2.
Normally, you don't want users to see assertion messages in production code; assertions are primarily for use during development and maintenance. Assertions are normally compiled into the code at development time and compiled out of the code for production.
但是,在同一部分的后面,提供了以下建议:
For highly robust code, assert and then handle the error anyway.
我认为,只要性能不是问题,就保留断言,而不是显示消息,而是将其写入日志文件。我认为建议也包含在"代码完成"中,但我现在找不到。
回答
我们的数据库服务器软件包含生产和调试断言。调试断言只是-在生产代码中将它们删除。仅当(a)存在一些本不应该存在的条件并且(b)无法可靠地从该条件中恢复时,才会产生生产断言。生产断言表明已遇到软件错误或者发生了某种类型的数据损坏。
由于这是一个数据库系统,并且我们正在存储潜在的企业关键数据,因此我们将尽一切可能避免损坏数据。如果存在可能导致我们存储错误数据的条件,我们将立即声明,回滚所有事务并停止服务器。
话虽如此,我们还试图避免在性能关键型例程中进行生产断言。
回答
在我的C ++中,我定义REQUIRE(x)类似于assert(x),不同之处在于,如果在发布版本中断言失败,则它会引发异常。
由于断言失败表明存在错误,因此即使在发布版本中也应认真对待它。当我的代码的性能很重要时,我经常将REQUIRE()用于高级代码,将assert()用于必须快速运行的低级代码。如果失败情况可能是由第三方编写的代码传入的数据或者文件损坏引起的,我也使用REQUIRE而不是断言(最佳情况下,我将代码设计为在文件损坏的情况下表现良好,但我们并非总是有时间这样做。)
他们说我们不应该向最终用户显示那些断言的消息,因为他们不会理解它们。所以?最终用户可能会向我们发送包含屏幕截图或者错误消息文本的电子邮件,以调试。如果用户只是说"它崩溃了",则我们修复它的能力将降低。最好通过Internet自动向我们发送断言失败消息,但这仅在用户可以访问Internet并且我们可以征得他们的许可的情况下才有效。
回答
断言是不会过时的注释。他们记录了预期的理论状态,以及不应发生的状态。如果代码被更改,从而说明允许更改,则开发人员将很快得到通知,并需要更新断言。
回答
使断言在生产代码中保持打开状态,除非我们已断言它们已使程序运行得明显更快。
if it's not worth measuring to prove it's more efficient, then it's not worth sacrificing clarity for a performance gamble." - Steve McConnell 1993
http://c2.com/cgi/wiki?ShipWithAssertionsOn