c++中的断言是如何实现的?示例代码表示赞赏。
8 回答
断言是一种明确检查代码所做假设的方法,它可以帮助您通过缩小可能出现的问题来跟踪大量错误。它们通常只在应用程序的特殊“调试”版本中进行评估,因此它们不会减慢最终发布版本的速度。
假设您编写了一个将指针作为参数的函数。您的代码很有可能会假定指针为非 NULL,那么为什么不使用断言显式检查呢?就是这样:
#include <assert.h>
void function(int* pointer_arg)
{
assert(pointer_arg != NULL);
...
}
需要注意的重要一点是,您断言的表达式绝不能有副作用,因为它们不会出现在发布版本中。所以永远不要做这样的事情:
assert(a++ == 5);
有些人还喜欢在他们的断言中添加一些小信息来帮助赋予它们意义。由于字符串总是评估为真,你可以这样写:
assert((a == 5) && "a has the wrong value!!");
断言是布尔表达式,通常应该始终为真。
它们用于确保您所期望的也会发生。
void some_function(int age)
{
assert(age > 0);
}
你编写了处理年龄的函数,你也“知道”你总是在传递合理的参数,然后你使用断言。这就像说“我知道这永远不会出错,但如果真的出错了,我想知道”,因为,嗯,每个人都会犯错。
因此,不要检查合理的用户输入,如果有可能出现问题的场景,请不要使用断言。进行真正的检查并处理错误。
断言通常仅用于调试构建,因此不要将具有副作用的代码放在断言中。
断言用于验证设计假设,通常根据输入参数和返回结果。例如
// Given customer and product details for a sale, generate an invoice
Invoice ProcessOrder(Customer Cust,Product Prod)
{
assert(IsValid(Cust));
assert(IsValid(Prod);
'
'
'
assert(IsValid(RetInvoice))
return(RetInvoice);
}
代码运行不需要断言语句,但它们检查输入和输出的有效性。如果输入无效,则调用函数中存在错误。如果输入有效而输出无效,则此代码存在错误。有关断言的这种使用的更多详细信息,请参见按合同设计。
编辑:正如其他帖子中所指出的,assert 的默认实现不包含在发布运行时中。许多人(包括我自己)会使用的一种常见做法是将其替换为发布版本中包含的版本,但仅在诊断模式下调用。这可以通过完整的断言检查对发布版本进行适当的回归测试。我的版本如下;
extern void _my_assert(void *, void *, unsigned);
#define myassert(exp) \
{ \
if (InDiagnostics) \
if ( !(exp) ) \
_my_assert(#exp, __FILE__, __LINE__); \
} \
这种技术的运行时开销很小,但它可以更轻松地跟踪任何使其进入该领域的错误。
使用断言来检查“不可能发生”的情况。
典型用法:检查函数顶部的无效/不可能参数。
很少见到,但仍然有用:循环不变量和后置条件。
断言是允许您测试程序中可能存在的任何假设的语句。这对于记录程序逻辑(前置条件和后置条件)特别有用。失败的断言通常会引发运行时错误,并且表明您的程序存在严重错误 - 您的断言失败是因为您认为正确的事情不是。通常的原因是:你的函数逻辑有缺陷,或者你的函数的调用者传递了错误的数据。
断言是您添加到程序中的东西,如果满足条件,它会导致程序立即停止,并显示错误消息。您通常将它们用于您认为在您的代码中永远不会发生的事情。
这并没有解决从早期 C 时代就传给我们的断言工具,但是如果您的项目可以使用 Boost,您还应该了解Boost StaticAssert功能。
标准 C/C++ 断言在运行时工作。Boost StaticAssert 工具使您能够在编译时创建某些类的断言,甚至更早地捕获逻辑错误等。