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