我不明白assert()
的目的。
我的讲师说断言的目的是发现错误。
例如:
double divide(int a , int b )
{
assert (0 != b);
return a/b;
}
以上断言是否合理?我认为答案是肯定的,因为如果我的计划
不应该使用0
(数字零),但不知何故零确实进入b
变量,然后代码出错了。
我说错了吗?
你能告诉我一些合理的断言()的例子吗?
问候
答案 0 :(得分:16)
assert
用于验证应该始终为true的内容
程序是正确的。在您的示例中,assert
是否合理
取决于divide
的规范:如果b != 0
是先决条件,
那么assert
通常是验证它的首选方式:如果
有人在没有满足前提条件的情况下调用函数,它是一个
编程错误,你应该极端终止程序
偏见,做尽可能少的额外工作。 (平时。
有些应用程序不是这种情况,而是它的位置
最好抛出异常,然后绊倒,希望最好。)
但是,如果divide
的规范定义了b
== 0
时的somw行为(例如返回+/- Inf),那么您应该实现此而不是
使用断言。
此外,如果事实证明它可以关闭assert
需要太多的运行时间。但是,一般来说,这应该只在
代码的关键部分,并且只有在探查器显示您的情况下
真的需要它。
FWIW:与您的问题无关,但您发布的代码会有
返回0.0
divide( 1, 3 )
。不知何故,我不认为这是
你想要什么。
答案 1 :(得分:7)
断言的另一个方面:
它们也是一种文档。
而不是像
这样的评论// ptr is never NULL
// vec has now n elements
更好写
assert(ptr!=0);
assert(vec.size()==n);
评论可能会随着时间的推移而过时,并会引起混淆。 但断言一直在被证实 评论可以忽略。断言不能。
答案 2 :(得分:5)
你在assert
的评估中非常注意,除了你在调试阶段通常使用assert
的事实...这是因为你不想要一个assert
在生产代码中触发...抛出异常(并正确处理它们)是生产级代码中运行时错误管理的正确方法。
通常,assert
用于测试假设。如果在调试阶段代码中没有满足假设条件,特别是当您获得超出所需输入值的值时,您希望程序在遇到错误时挽救,这样您可以解决它。例如,假设您正在调用一个返回指针的函数,该函数应该从不返回NULL
指针值。换句话说,返回NULL
值不仅仅是错误条件的一些指示,但它意味着您对代码如何工作的假设是错误的。这是一个使用assert
的好地方...你假设你的程序将以一种方式工作,如果没有,那么你不希望该错误传播导致一些疯狂的难以找到的错误否则......你想在它发生时把它弄好。
最后,您可以将内置宏与assert
结合使用,例如__LINE__
和__FILE__
,它们会在代码中为您提供文件和行号以帮助您快速识别问题区域。
答案 3 :(得分:3)
断言的目的是在调试期间发出意外行为(因为它仅在调试版本中可用)。你的例子是断言的合理案例。下一行可能会崩溃,但使用断言,您可以选择在命中行之前中断执行,并进行一些调试。
这通常与异常并行完成 - 你断言要发出错误的信号,并抛出异常来优雅地处理案件(甚至退出程序):
double divide(int a , int b )
{
assert (0 != b);
if ( b )
return a/b;
throw division_by_0_exception();
}
在某些情况下,您希望继续执行,但仍希望发出错误信号。
答案 4 :(得分:1)
Assert用于在调试环境中测试有关代码的假设。断言通常对最终构建没有影响。
它是否是有效的测试完全是另一回事。如果不熟悉您的申请,我们无法回答这个问题。
断言永远不会失败。如果您发现断言可能会失败,那么您需要使用if语句来处理条件不正确的情况。断言仅适用于您认为永远不会失败的条件。
答案 5 :(得分:1)
断言用于在代码执行期间检查不变量,这些是程序员假设始终保持不变的条件,如果它们与假设不同则代码中存在错误。
断言也可以用于检查前置条件和后置条件,第一个在一些代码块之前检查并验证提供的数据/状态是否正确,第二个检查某些计算的结果是否正确。这有助于缩小可能存在问题/错误的位置:
assert( /*preconditions*/ );
/*here some algorithm - and maybe more asserts checking invariants*/
assert( /*postconditions*/ );
一些合理断言的例子:
WinAPI Thread32First函数要求提供的LPTHREADENTRY32结构已正确分配dwSize字段,如果出现错误则失败。断言应该抓住这个失败。
如果函数接受指向某些数据的指针,则在函数的开头添加assert以验证它是否为非null。如果此函数不能对空指针起作用,则这是有意义的。
如果锁定了具有设置超时的互斥锁,那么如果此超时结束,则可以使用assert来指示可能的竞争条件/死锁
......还有更多
断言的好处是在里面添加一些信息,例如:
断言(假和&&“这个断言的原因”);
“此断言的原因”将在消息框中显示给您
您可能还想知道我们还有静态断言,指示编译期间的错误。