Channels ▼

Andrew Koenig

Dr. Dobb's Bloggers

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

White Papers

More >>

Reports

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.

Related Reading






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips 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.
 


Video