Rogue Wave banner
Previous fileTop of documentContentsIndexNext file

17.5 The Debug Version of Tools.h++

You can build the Tools.h++ library in a debug mode, and gain a very powerful tool for uncovering and correcting internal errors in your code.

To build a debug version of the library, you must compile the entire library with the preprocessor flag RWDEBUG defined. You must compile the entire library and application with a single setting of the flag -- either defined or not defined. The resultant library and program will be slightly larger and slightly slower. See the appropriate makefile for additional directions.

The flag RWDEBUG activates a set of PRECONDITION and POSTCONDITION clauses at the beginning and end of critical functions. These pre- and postconditions are implemented with asserts. A failure will cause the program to halt after first printing out the offending condition, along with the file and line number where it occurred.

17.5.1 RWPRECONDITION and RWPOSTCONDITION

In his landmark book Object-oriented Software Construction, Bertrand Meyer suggests regarding functions as a contract between a caller and a callee. If the caller agrees to abide by a set of preconditions, the callee guarantees to return results that satisfy a set of postconditions. The following comparison shows the usefulness of Meyer's paradigm in Tools.h++. Let's look first at a bounds error in C:

char buff[20];
char j = buff[20];                               // Bounds error!

Such a bounds error is extremely tough to detect in C, but easy in C++, as shown below:

RWCString buff(20);
char j = buff[20];                     // Detectable bounds error

The bounds error is easy to detect in C++ because the operator[] can be overloaded to perform an explicit bounds check. In other words, when the flag RWDEBUG is set, operator[] also executes the PRECONDITION clause, as below:

char& RWCString::operator[](size_t I){
   RWPRECONDITION(i < length() );
   return rep[i];
}

The case just described would trigger a failure because operator[]would find that the PRECONDITION is not met.

Here's a slightly more complicated example:

template <class T> void List::insert(T* obj){
   RWPRECONDITION( obj!= 0 );
   head = new Link(head, obj);
   RWPOSTCONDITION( this->contains(obj) );
}

In this example, the job of the function insert() is to insert the object pointed to by the argument into a linked list of pointers to objects of type T. The only precondition for the function to work is that the pointer obj not be null. If this condition is satisfied, then the function guarantees to successfully insert the object. The condition is checked by the postcondition clause.

The macros RWPRECONDITION and RWPOSTCONDITION are defined in <rw/defs.h> and compile out to no-ops, so long as the preprocessor macro RWDEBUG is not defined. Here's what appears in the makefile:

#ifdef RWDEBUG
#  define RWPRECONDITION(a)      assert(a)
#  define RWPOSTCONDITION(a)     assert(a)
#else
#  define RWPRECONDITION(a)      ((void*)0)
#  define RWPOSTCONDITION(a)     ((void*)0)
#endif


Previous fileTop of documentContentsIndexNext file
©Copyright 1999, Rogue Wave Software, Inc.
Send mail to report errors or comment on the documentation.