开发者

Using "assert" with pointers in C++

开发者 https://www.devze.com 2022-12-13 12:41 出处:网络
When d开发者_C百科o we need to use \"assert\" for pointers in C++, and when they are used, how are they most commonly implemented?Generally you would use an assert to check a condition that, if false,

When d开发者_C百科o we need to use "assert" for pointers in C++, and when they are used, how are they most commonly implemented?


Generally you would use an assert to check a condition that, if false, would indicate a bug in your application. So if a NULL pointer shouldn't ever be encountered at some point in the application, unless there's a bug, then assert it. If it might be encountered due to some invalid input then you need to do proper error handling.


You don't need to use assert on pointers at all. The idea is to ensure you don't crash when dereferencing your pointers when they're null.

You can do this with assert but it's not a very professional way to handle errors like this since it invariably terminates the program - not a good idea if the user hasn't, for example, saved their last three hours worth of data entry.

What you should do with pointers is to check them for null-ness and fail gracefully. In other words, have your function return an error of some sort or do nothing (not everyone will agree with this approach but it's perfectly acceptable if it's documented).

The assert stuff is meant, in my opinion, for catching problems during development which is why you'll find assert does nothing in release builds under some compilers. It is not a substitute for defensive programming.

As to how to do it:

#include <assert.h>
void doSomethingWithPointer (int *p) {
    assert (p != 0);
    cout << *p << endl;
}

but this would be better done as:

void doSomethingWithPointer (int *p) {
    if (p != 0)
        cout << *p << endl;
}

In other words, even if your "contract" (API) states that you're not allowed to receive null pointers, you should still handle them gracefully. An old quote: be conservative in what you give, liberal in what you accept (paraphrased).


ASSERT statements are great as "enforced documentation" - that is, they tell the reader something about the code ("This should never happen") and then enforces it by letting you know if they don't hold true.

If it's something that could happen (invalid input, memory not able to be allocated), that's not a time to use ASSERT. Asserts are only for things that can not possibly happen if everyone is obeying pre-conditions and such.

You can do it thusly:

ASSERT(pMyPointer);


From experience if you assert on null conditions that should never happen under normal conditions you program is in a really bad state. Recovering from such null condition will more likely than not mask the original problem.

Unless you code with exception guarantee in mind (linky) I say let it crash, then you know you have a problem.


I would use an ASSERT where a null pointer wouldn't immediately cause a crash but might lead to somethign wrong later that's hard to spot.
eg:

ASSERT(p);   
strcpy(p, "hello");

Is a little unnecessary, it simply replaces a fatal exception with a fatal assert!
But in more complex code, particulalrly things like smart pointers, it might be useful to know check if the pointer is what you thing it is.

Remember ASSERTs only run in debug builds, they dissapear in the release.


In C, there also assert function.. in debug mode, if assert(x), x condition is false, there will pop up an alert... But remember it works only in debug mode... in release mode, all assert functions are all skipped


Assertions are used to to define how the program should function. That being said, the most common use of Assert()s when dealing with pointers is going to either be that they are valid (non-NULL and point towards valid memory) or that their internal state is valid if they point to an object/class instance, for example.

Assertions are not for replacing or acting as error condition code, but instead to enforce rules that you are placing on the functioning of your code, such as what conditions should be at given points in time.

For example,

    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;
    }

Many users of Asserts choose to apply Assertions to internal state validation once they become familiar with them. We call these Invariants() which are methods on a class that assert many things about the internals of the object that should always hold true.

For example:

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

The important thing to remember is that this is to make sure that when bugs do happen that mean the program is not working as you would expect, then the effect of the bug happens as close to where it happened in the code as possible in order to make debugging easier. I have used Asserts extensively in my own code and while at Microsoft and I swear by them since they have saved me so much time in debugging and even knowing the defect is there.

0

精彩评论

暂无评论...
验证码 换一张
取 消