FREE Subscription to Dr. Dobb’s Digest: Same Great Content, New Digital Edition
Site Archive (Complete)
C++ Blog: Assertions versus exceptions
C++
void main(void)

Calls, Returns and In-Between.

by Kevin Carlson
SELECTIVE IGNORANCE

Finding the Signal in the Noise

by Andrew Koenig
July 14, 2007

Assertions versus exceptions

Thinking about how to deal with incorrect input reminded me of a place where I used to work. We were building C++ class libraries to distribute to other developers in the company, and our managers imposed a rule: No code delivered to customers could contain an assert statment.

The reasoning was simple, at least in theory: Our customers might use our code in high-reliability systems. An assert causes the entire program to terminate if the condition asserted is false, and the view was that under no conditions could we ever do anything that might terminate the entire program.

Interestingly, this took place before C++ had exceptions, which meant that there was no way of dealing with "impossible" conditions: All a program could do under such circumstances was return an error indication to its caller--an indication that the caller would probably ignore.

Today, of course, we have exceptions; a fact that gives us the opportunity to decide when we should use an exception and when we should use an assert. There are two important differences between an exception and an assert: (1) It is possible to decide during compilation that assert statements should be ignored, and (2) If an assert is executed (i.e. not ignored) and its condition turns out to be false, the caller of the program that contains the assert can't do anything about it.

So the question comes down to this: Is it ever right to terminate a program unconditionally?

The people in charge of the organization in which I worked at the time said no--total termination was something that we could never afford. But I thought then, and I still think, that this view was naive.

For one thing, if you think you can prevent a C++ program from terminating by removing the assert statements, you are seriously mistaken. It is true that by doing so, you make it less likely that the program will crash; but if a crash is something you can never afford, it is far from clear that making a crash less likely is an advantage. After all, by doing so, what you are really doing is making it easier to pretend that a crash will never happen, thereby making the situation that much worse when it does happen.

Moreover, removing assert statements will not keep a program from crashing if it tries to use an invalid pointer, or index past the end of an array, or (on most machines) divide by zero.

Not only that, but it is sometimes right to use an assert instead of an exception. The most common situation that comes to mind is when a program discovers a situation that the programmer believes is impossible. I'm not talking here about mere invalid input, but about a state of affairs that indicates that the program itself is broken in unanticipated ways.

For example, consider a program that implements a doubly-linked list. Such a list might be represented as a collection of nodes, each of which has pointers to its prececessor and successor. In such a program, one can reasonably expect that if p points to a node, and that node has a successor (i.e. it is not at the end of the list), then the successor will point back at the original node as its predecessor. One might incorporate that belief into one's program as

    assert (p->succ == 0 || p->succ->pred == p);

If this assert ever fails, it means that the data structure has become corrupted, and any attempt to use it further will have undefined consequences. It is true that the program might be able to continue in these circumstances, provided that it never tried to use the errant pointer, but if the program produces correct results after that, it does so only by coincidence.

I believe, therefore, that when a program discovers something that is irrefutably wrong with its internal state, it is better off terminating at once, rather than giving its caller the opportunity to pretend that nothing is wrong.

If you like, I think that exceptions should be reserved for situations in which it is possible to do something sensible after catching the exception. When you discover a condition that you thought was impossible, it's hard to say much about what might happen afterward.

Posted by Andrew Koenig at 04:15 PM  Permalink




 
INFO-LINK