我们什么时候需要在C ++中使用“assert”指针,当它们被使用时,它们最常被实现?
答案 0 :(得分:13)
通常,您将使用断言来检查条件,如果为false,则表示应用程序中存在错误。因此,如果在应用程序的某个时刻遇到不应该,那么除非有错误,否则断言它。如果由于某些无效输入而遇到它,那么您需要进行适当的错误处理。
答案 1 :(得分:4)
你根本不需要对指针使用断言。我们的想法是确保在指针取消引用时它们不会崩溃。
你可以用assert
做到这一点,但这不是一个非常专业的方法来处理这样的错误,因为它总是终止程序 - 如果用户没有,例如,保存他们的最后三个不是一个好主意小时数据输入。
使用指针执行的操作是检查它们是否为null,并且优雅地失败。换句话说,让你的函数返回某种错误或什么都不做(不是每个人都会同意这种方法,但如果记录的话,它是完全可以接受的。)
在我看来,assert
的东西意味着在开发期间捕获问题,这就是为什么你会发现assert在某些编译器下的发布版本中什么都不做。 不是防御性编程的替代品。
至于如何做到这一点:
#include <assert.h>
void doSomethingWithPointer (int *p) {
assert (p != 0);
cout << *p << endl;
}
但最好这样做:
void doSomethingWithPointer (int *p) {
if (p != 0)
cout << *p << endl;
}
换句话说,即使您的“合同”(API)声明您不允许接收空指针,您仍然应该优雅地处理它们。一句老话:在你所给予的内容中保守,在接受的内容中是自由的(释义)。
答案 2 :(得分:4)
ASSERT语句非常适合作为“强制文档” - 也就是说,它们告诉读者一些关于代码的信息(“这应该永远不会发生”),然后通过让你知道它们是否不成立来强制执行它。
如果可能发生(无效输入,无法分配内存),那么不时间使用ASSERT。如果每个人都遵守前提条件等,那么断言只有 才能发生。
你可以这样做:
ASSERT(pMyPointer);
答案 3 :(得分:2)
根据经验,如果你在正常情况下永远不会发生的空条件断言你编程处于非常糟糕的状态。从这种空状态恢复将更有可能掩盖原始问题。
除非你考虑到异常保证(linky),否则我说让它崩溃,然后你知道你有问题。
答案 4 :(得分:0)
我会使用一个ASSERT,其中一个空指针不会立即导致崩溃,但可能会导致某些错误,以后很难发现。
例如:
ASSERT(p);
strcpy(p, "hello");
有点不必要,它只是用致命的断言替换致命的异常! 但是在更复杂的代码中,特别是像智能指针这样的东西,知道检查指针是否就是你的东西可能是有用的。
请记住,ASSERT仅在调试版本中运行,它们在发行版中消失了。
答案 5 :(得分:0)
在C中,还有断言功能.. 在调试模式下,如果断言(x),x条件为假,则会弹出警报... 但请记住它仅适用于调试模式... 在发布模式下,所有断言功能都被跳过
答案 6 :(得分:0)
断言用于定义程序应如何运行。话虽这么说,在处理指针时,Assert()的最常见用法是它们是有效的(非NULL并指向有效的内存),或者如果它们指向对象/则它们的内部状态是有效的。例如,类实例。
断言不是用于替换错误条件代码或充当错误条件代码,而是用于实施要在代码功能上放置的规则,例如,在给定的时间点应满足哪些条件。
例如,
function int f(int x, int * pY)
{
// These are entrance conditions expected in the function. It would be
// a BUG if this happened at all.
Assert(x >= 0);
Assert(pY != nullptr);
Assert(*pY >= 0, "*pY should never be less than zero");
// ...Do a bunch of computations with x and pY and return the result as z...
int z = x * 2 / (x + 1) + pow(*pY, x); // Maybe z should be always positive
// after these calculations:
Assert(x >= 0, "X should always be positive after calculations);
// Maybe *pY should always be non-zero after calculations
Assert(*pY != 0, "y should never be zero after computation");
Assert(z > 0):
return z;
}
许多断言的用户在熟悉断言后便选择将断言应用于内部状态验证。我们称这些Invariants()为类中的方法,这些方法断言关于对象内部的许多事情,这些事情应始终成立。
例如:
class A
{
public:
A(wchar_t * wszName)
{
_cch = 0;
_wszName = wszName;
}
// Invariant method to be called at times to verify that the
// internal state is consistent. This means here that the
// internal variable tracking the length of the string is
// matching the actual length of the string.
void Invariant()
{
Assert(pwszName != nullptr);
Assert(_cch == wcslen(pwszName));
}
void ProcessABunchOfThings()
{
...
}
protected:
int _cch;
wchar_t * pwszName;
}
// Call to validate internal state of object is consistent/ok
A a(L"Test Object");
a.Invariant();
a.ProcessABunchOfThings();
a.Invariant();
要记住的重要一点是,要确保当确实发生错误时,这意味着程序无法按预期工作,那么,错误的影响会尽可能地接近代码中发生的地方为了使调试更容易。我在自己的代码中广泛使用了Asserts,而在Microsoft时,我对它们发誓,因为它们为我节省了很多时间进行调试,甚至不知道存在缺陷。