SafeInt
Next: SafeFloat
Up: TECHNIQUES AND EXAMPLES
Previous: TECHNIQUES AND EXAMPLES
The following simple code illustrates many of C++'s features for controlling
access to data.
Following the class definition, the general use of some C++ features in safety
critical code and some comments specific to class SafeInt are discussed.
Note that in practice this class would occupy two files:
SafeInt.h would include the declaration of the class, its attributes
and functions, while SafeInt.c++ would include the definitions (bodies) of
the functions.
The two are combined below for exposition purposes.
[ 1] class SafeInt
[ 2] {
[ 3] private:
[ 4] long int i; // the actual value of the safe integer
[ 5] operator int() const { return i;}
[ 6]
[ 7] public:
[ 8] SafeInt(const SafeInt other) { i = other.i;}
[ 9] SafeInt() { i = 0;}
[10] SafeInt(const int value) { i = value;}
[11] ~SafeInt() {}
[12]
[13] SafeInt operator= (const SafeInt value) { i = value.i; return(*this);}
[14] SafeInt operator= (const int value) { i = value; return(*this);}
[15] SafeInt operator+ (const int b) const { return(SafeInt(i+b));}
[16] SafeInt operator+ (const SafeInt b) const { return(SafeInt(i+b.i));}
[17] SafeInt operator/ (const SafeInt b) const { if (b.i == 0) ... else ...}
[18] SafeInt operator% (const SafeInt b) const { ... }
[19] int operator!= (const SafeInt b) const { return(i != b.i);}
[20] SafeInt operator++ () { i++; return(*this);}
[21] SafeInt operator++ (int _) { SafeInt t = *this; i++; return(t);}
[22] int value() {return i;}
[23] };
Notes
-
Line [4] declares i the attribute that holds the actual value of the
SafeInt.
-
Because there is only one attribute, objects of class SafeInt are small
and thus efficiently passed as call-by-value parameters.
To pass larger objects, use constant reference parameters (see R4.1.6).
For example, if SafeInt's were larger, the addition operator would have
been declared
SafeInt operator+ (const SafeInt &b);
Declaring a parameter (const &) preserve the semantics of values
parameter passing, without the cost of copying large data structures.
-
Every class should include a copy constructor (Line [8]), a default constructor
(Line [9]), and an assignment operator (Line [13]).
Failure to do so causes C++ to include default definitions that may have
undesirable effects.
If any of these operations is not desired its definition should be declared in
the private part of the class.
In particular, control of the copy constructor and assignment operator can be
used to limit the number of objects of a class that are created.
-
If the copy constructor (Line [8]) is moved to the private section
of the class, then definitions of the form
SafeInt ss = si;
are flagged as errors by the compiler.
-
If the default constructor (Line [9]) is moved to the private section
of the class, then declarations of the form
SafeInt si;
are flagged as errors by the compiler.
In this situation, no uninitialized SafeInt's can be constructed.
Only SafeInts constructed from other SafeInts (Line [8]) or
ints (Line [10]) are allowed.
-
Finally, if the assignment operator (Line [13]) is moved to the private
section of the class, then assignment to SafeInts is not permitted;
thus, statements such as
si1 = si2;
are flagged as errors by the compiler.
-
Line [5] provides a ``use as an integer'' operator, which is implicitly called
in any context where an int is required, but a SafeInt is given.
If public, it would allow unwanted implicit (unwanted) use of
SafeInts.
By making it private, the compiler issues an error message when a
SafeInt is used in such a context.
Many compilers will issue such messages if the definition is simply omitted,
but providing such a definition in the private section makes explicit that
a SafeInt should not be implicitly converted to an int.
Explicit access can be provided via another access function, such as the function
value() (Line [22]).
This function should return a copy of the object;
thus, preventing the caller from modifying the object.
(Returning an int returns a copy of the int so no explicit
copying is shown in the code.)
Thus, SafeInt explicitly allows the programmer to control or avoid unwanted
type conversions.
-
The assignment operator on Line [14] assigns an int to a SafeInt.
Code checking the validity of the int could be placed in this function.
For example, if SafeInts had to be less than 1000, that check could be
made here.
If this operator is omitted, then the int would be converted to a
SafeInt using the constructor on Line [10] and then assigned using the
assignment operator on Line [13].
(If both are present the assignment operator on Line [14] is used.)
-
Similarly the operator on Line [15] performs the addition of a SafeInt
and an int.
Without this operator the int would first be converted into a
SafeInt using the constructor on Line [10] then added using the addition
operator on Line [16].
-
There are two reasons having SafeInt as a class is an advantage:
first, the built-in types char, int, and float (including
modified versions unsigned char, long int, etc.) are not classes.
This makes the build-in types unusable in certain contexts (e.g., at
least one of the parameters of an overloaded operator must be of class type).
It also prohibits their being used as base classes (e.g., to declare a
subrange class).
-
The second reason for having a class such as SafeInt is that it allows
operators like division and remainder to have consistent predictable behavior:
C++ leaves the definition of integer remainder up to the compiler writer.
Most compiler writers use the hardware divide instruction for computing integer
remainders.
Unfortunately, some hardware divide instructions ensure that the remainder is
positive while others do not.
In class SafeInt,
operator% can provide consistent results (unlike C++'s default %
operator).
As an added bonus, operator/ can also check for division by zero.
-
Use of the classes SafeInt and SafeUnsignedInt (not shown) prevents
the mixing of signed and unsigned numbers.
For example, many C++ compilers accept the following code.
{
unsigned a = 1;
int i = -5;
a = i;
}
Next: SafeFloat
Up: TECHNIQUES AND EXAMPLES
Previous: TECHNIQUES AND EXAMPLES
David Binkley
Thu Feb 29 10:02:46 EST 1996