|
|
The following is an example of a client error in the use of the String(C++) component:
#include <String.h> main() { String x = "hello world"; char c = x[24]; }The client has made an error by attempting to extract the 24th character from a String having only 11 characters (numbered 0 through 10). How should this error be treated?
One possibility would be for the square brackets operator to check its argument and take some well-defined action if the check indicates a bad subscript:
char String::operator[](unsigned i) { if (i >= length of this String ) { do something to signal an error } }However, a programmer who knows that the operator is being used properly will surely object: ``Why should I have to pay for checking something I already know to be correct?'' For this reason, our components never check for client errors. For the String component, this fact is documented in the form of a precondition on the use of the square brackets operator. The following excerpt is from the String(C++) manpage:
char operator[](unsigned i); Returns character number i. Precondition: i must be less than the length of the String.
Failure to satisfy a precondition leads to undefined behavior. A core dump or an infinite loop might result; even worse, a problem might not turn up until much later in a way that would be difficult to trace.
There are generally two ways to avoid client errors:
String x; ... for (unsigned i = 0;i<x.length();i++) { char c = x[i]; ... }is correct because i takes only values that satisfy the precondition.
String x; unsigned i; ... if (i < x.length()) { char c = x[i]; ... } else { do something else }Note that when this is done, the cost of checking is allocated to the client, not the component.
#include <Map.h> // Map.h contains template class definitions for // instantiating two classes: Map<int,int> and // Mapiter<int,int> main() { Map<int,int> m; m[24] = 1; }Initially, the Map m has no elements. Attempting to assign to the 24th element, as in the above example, might be construed as analogous to attempting to access to the 24th character of a short String. However we decided that the effect of the square brackets operator should be well-defined for all possible keys. The effect is as follows: if a given key is referenced and a pair with that key does not exist in the Map, then a new pair will be created with this key. Thus a condition with potentially disastrous (and completely undefined) behavior is transformed into a condition with well-defined (though not necessarily intuitive) behavior.