在 C++ 中使用带有指针的“assert”

问题描述 投票:0回答:7

我们什么时候需要对 C++ 中的指针使用“assert”?何时使用它们,它们最常见的实现方式是什么?

c++ pointers assert
7个回答
15
投票

通常,您会使用断言来检查条件,如果条件为假,则表明应用程序中存在错误。因此,如果在应用程序中的某个时刻“不应该”遇到 NULL 指针(除非存在错误),则断言它。如果由于某些无效输入而可能遇到这种情况,那么您需要进行适当的错误处理。


8
投票
对指针使用断言。这个想法是为了确保当指针为空时取消引用它们时不会崩溃。

您可以使用 assert

执行此操作,但这不是处理此类错误的非常专业的方法,因为它总是会终止程序 - 例如,如果用户没有保存最后三个小时的数据,那么这不是一个好主意进入。

应该

对指针做的是检查它们是否为空(或任何其他有问题的条件)并

优雅地失败。换句话说,让你的函数返回某种错误或什么都不做(不是每个人都会同意这种方法,但如果有记录的话,这是完全可以接受的)。 在我看来,assert

的东西是为了在

开发

期间捕获问题,这就是为什么你会发现assert在某些编译器下的发布版本中没有任何作用。它
不能替代防御性编程。 至于如何做:

#include <assert.h> void doSomethingWithPointer (int *p) { assert (p != 0); // does *nothing* if `NDEBUG` set. cout << *p << endl; }

但这会更好,比如:
void doSomethingWithPointer (int *p) {
    if (p != 0)  // protects against null pointer always.
        cout << *p << endl;
}

换句话说,即使你的“合约”(API)规定你不允许接收空指针,你仍然应该优雅地处理它们。一句古老的名言:
在你所给予的方面要保守,在你接受的方面要自由
(释义)。

ASSERT 语句非常适合作为“强制文档”——也就是说,它们告诉读者有关代码的一些信息(“这永远不应该发生”),然后通过让您知道它们是否不成立来强制执行它。

4
投票
如果这是

可能

发生的事情(无效输入、无法分配内存),那就是

使用ASSERT的时候。断言适用于如果每个人都遵守先决条件等就不可能发生的事情。 你可以这样做:

ASSERT(pMyPointer);

根据经验,如果您断言空条件,在正常情况下应该“永远不会发生”,那么您的程序处于非常糟糕的状态。从这种空条件中恢复更有可能掩盖原始问题。

2
投票
除非你在编码时考虑到异常保证(

linky)我说让它崩溃,那么你就知道你有问题。

我会使用 ASSERT,其中空指针不会立即导致崩溃,但可能会导致稍后难以发现的错误。 例如:


0
投票

有点不必要,它只是用致命断言替换致命异常!
但在更复杂的代码中,特别是像智能指针这样的代码,了解检查指针是否是您想要的可能会很有用。

记住 ASSERT 仅在调试版本中运行,它们在版本中消失。


在C中,还有assert函数.. 在调试模式下,如果断言(x),x条件为假,则会弹出警报... 但请记住它仅在调试模式下有效...... 在release模式下,所有assert函数都会被跳过


0
投票
断言用于定义程序应如何运行。话虽这么说,在处理指针时,Assert() 最常见的用途是它们是有效的(非 NULL 并指向有效内存),或者如果它们指向一个对象/,则它们的内部状态是有效的。例如,类实例。

断言不是为了替换或充当错误条件代码,而是为了强制执行您对代码功能设置的规则,例如在给定时间点应满足哪些条件。

0
投票
例如,

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();

要记住的重要一点是,这是为了确保当错误确实发生时,这意味着程序没有按您预期的方式工作,然后错误的影响尽可能接近代码中发生的位置,以便按顺序发生使调试更容易。我在自己的代码中以及在 Microsoft 期间广泛使用了断言,我对它们发誓,因为它们为我节省了很多调试时间,甚至知道存在缺陷。


© www.soinside.com 2019 - 2024. All rights reserved.