【发布时间】:2010-04-15 02:43:57
【问题描述】:
另外,它与出错时抛出异常相比如何?
【问题讨论】:
-
Err.. VERIFY() 是什么?它不在 c++ 标准库中……您的意思是断言语句吗?
-
我想知道为什么标准库有 assert() 而没有 verify()
标签: c++ coding-style verify
另外,它与出错时抛出异常相比如何?
【问题讨论】:
标签: c++ coding-style verify
VERIFY() 与ASSERT()(或标准库assert())具有相同的目的 - 让您捕捉到真正不应该™正在发生的事情(即真正的代码错误,应该在发布之前修复)。如果由于某种原因表达式是错误的,那么就没有必要继续下去了,因为某些事情非常非常糟糕。
这反映在 VERIFY() 在调试模式下编译时仅在错误评估时停止程序 - 在发布模式下,它是透明的。 VERIFY() 和 ASSERT() 之间的区别在于 VERIFY() 仍然会在发布模式下评估表达式,它根本不关心结果 - 而 ASSERT() 在发布模式下编译时完全从程序中删除并且因此不会发生其中的表达式的任何副作用。
异常对于可能出错的事情更有用,但可以从中恢复,因为异常可以由程序的其他部分处理。
【讨论】:
这个问题看起来很简单,但隐藏了一个巨大的主题:处理错误。
总的来说,我想说 assert 和 verify 是在开发过程中使用的工具,而 exceptions 和系统调用错误检查是生产代码的正常部分,用于处理运行时错误。
断言(它适用于断言和验证)是主要用于防御性编程风格的工具。他们的主要目标是防止出现不应该发生的情况,而程序员不知道如果发生这种情况该怎么办。通常用于检查编程错误。当调试程序时发生不可能的事情时,您通常希望尽快检测并报告它。它将简化纠错。您可以在某些条件下使用它,甚至可以将其用作 assert(false),通常用于检查开关的分支是否从未被捕获。
在处理行为我不确定的第三方代码时,我主要使用断言。为了检查我自己正在开发的代码的行为,我通常更喜欢单元测试。
现在,正如薛定谔教导我们的那样,措施改变了一切。当启用断言并停止在发布模式下工作时,您有时可能会拥有在调试模式下工作的代码。它通常是断言条件中隐藏错误的症状(副作用,时间敏感代码)。验证将这种风险降到最低,但这可能被认为是一种不好的做法,例如扫地毯后面的灰尘。
您还可以使用 verify 进行快速编码,作为尚未设置真正错误处理的地方的支架。我认为您不应该在生产代码中进行任何验证。
异常是程序控制流的正常部分。大多数情况下,它们用于处理错误,但这并不是它们唯一可能的用途(那些使用其他语言如 python 的人会知道我在说什么)。它们也不应被视为唯一的错误管理工具。当未包装在可识别 c++ 的库中时,系统调用仍会返回错误代码,而不是引发异常。
根据经验,异常应该被能够合理处理它们的最近对象捕获。
此外,并非所有异常都应视为致命错误并停止程序。想象一下,您正在处理一个通过异常返回错误案例的网络视频流库。如果库抛出一个帧被丢弃的异常警告,您通常不想停止程序而只是让它为下一帧做好准备。
即使最好的办法是停止程序,您也不应该让异常为您执行此操作(而且您甚至没有理由在生产代码中为此目的使用断言)。为此目的,应该始终存在一个顶级异常处理程序,该处理程序显式调用 exit() 之类的。不这样做只是表明程序员不关心可能发生的事情,并且可能没有考虑过。
【讨论】:
在 Visual C++ 中,有两个宏用于检查条件:ASSERT 和 VERIFY。
在调试模式下,它们的行为相同:即,它们都评估它们的参数,如果结果为 0,它们都会通过断言失败对话框停止程序。
区别在于发布模式。在发布模式下,ASSERT 完全从程序中删除:它根本不评估它的表达式。另一方面,VERIFY 仍然计算表达式,它只是忽略了结果。
个人,我的观点是,如果检查在调试模式下有价值,那么它在发布模式下也很有价值,你可能不应该使用它们中的任何一个。只需进行测试并引发异常(或使用自定义宏,在调试模式下扩展为 assert(),在发布模式下引发异常)。
【讨论】:
ASSERT() 中,然后不用担心发布模式下的性能损失。