Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.

# Assert Statements Shine Light Into Dark Corners

November 01, 2012

Last week, I introduced the notion of an invariant. Invariants are an unusual concept because our programs usually do not check them. Instead, invariants are intellectual tools that programmers use to think about how their programs work. We continue by exploring the consequences of checking that invariants actually hold when they should — a state of affairs that in principle should always be true.

## More Insights

More >>

More >>

### Webcasts

More >>

We used as an example last week a `vector`, `v`, with elements that we assume are sorted. We explained that because the elements were sorted, we could use a binary-search algorithm to find values in the `vector`, and in exchange for that convenience, we had to ensure that the elements actually were sorted whenever we were done working with them.

What we didn't talk about was what happens if the `vector` somehow winds up getting out of sequence, and how to detect that it has done so. If our code is written correctly, that should never happen — which, of course, is why we feel free about writing code in the first place that assumes that the `vector` is in sequence. However, precisely because we believe such conditions should never happen, we tend not to think about that possibility. As a result, when invariants do turn out to be false during program execution, the result often appears as a failure in what looks at first like an unrelated part of the program. We call such a situation an invariant failure; such failures can be very hard to trace.

Among the easiest ways to avoid invariant failures is to use `assert` statements to detect them. Technically speaking, the `assert` statement in C++ is a preprocessor macro, not a statement, but it behaves similarly to a statement. It takes the form

```
assert(expression);
```

and either tests the expression or does nothing, depending on whether the preprocessor macro `NDEBUG` is defined at the point in the program that contains the `assert`. If `NDEBUG` is not set, the expression is tested; if the test yields false (i.e., zero), the entire program is terminated.

The idea, then, is that the `NDEBUG` macro is used to turn off "debugging mode," and if a program is compiled in debugging mode, encountering an `assert` statement verifies that the expression given as its argument is true. So, for example, we can write a statement such as

```
assert(is_sorted(v));
```

before we try to use a binary-search algorithm on `v`. If the program is compiled in debugging mode, the `assert` will call `is_sorted`, which can check whether `v` is actually sorted. If, on the other hand, the program is compiled in production mode, the entire `assert` statement does nothing.

Using `is_sorted` in this way is a good example of why `assert` is useful. We do not want to call `is_sorted` every time we use `v`, because if we could afford to do so, we could probably also have chosen algorithms that do not require `v` to be sorted at all. On the other hand, being able to turn on debug mode and have `is_sorted` called for us is useful: Whenever the program is misbehaving in ways that "can't happen," we can turn on debug mode, recompile the program, and quickly learn whether the problem is an invariant failure.

Because `assert` is implemented as a macro, turning on `NDEBUG` completely eliminates the code that tests the condition. This behavior has the obvious advantage that there is no overhead attached to using `assert` when it is not needed. However, there is a more subtle advantage to using `assert` rather than exceptions to handle invariant failure: An invariant failure is a clear sign that the program is broken. If you like, the point of `assert` is to handle situations that "can't happen." When such a situation happens anyway, it's hard to say what code that catches an exception might do, because that code might rely on information that is wrong because of the invariant failure.

Despite the foregoing discussion, there is one big disadvantage to using `assert`: When an `assert` fails, the program terminates. This property of `assert` is hard to accommodate in systems that need to keep running. It's unacceptable for a program such as a word processor to terminate with an assertion failure simply because the user happened to do something that triggered a previously undetected bug. And yet the whole reason for using an `assert` is to ensure that the program does not quietly continue producing nonsense results because the conditions that it expected to find do not exist.

In effect, by catching invariant failures as they happen, `assert` makes programs more likely to produce correct results — if they produce results at all. This behavior leaves unanswered the question of how one deals with the failed invariants. We shall discuss strategies for doing so next time.

 To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.