C++ : Debugging and error handling
PART 9
Q39: How can I handle a constructor that fails?
A: Constructors (ctors) do not return any values, so no returned error code
is possible. There are many possibilities for how to handle this, one of
which is to set the object itself into a `half baked' state by setting an
internal status bit. Naturally there should be a query (`inspector') method
to check this bit, allowing clients to discover whether they have a live
object. Other member functions should check this bit, and either do a no-op
(or perhaps something more obnoxious such as `abort()') if the object isn't
really alive. Check out how the iostreams package handles attempts to open
nonexistent/illegal files for an example of prior art.
One more thing: you might want to store information indicating *why* the
failure took place in addition to a `failure bit'.
When real exceptions come to C++, they will provide a better strategy; the best
technique will generally be to throw an exception.
Q40: How can I compile-out my debugging print statements?
A: This will NOT work, since comments are parsed before the macro is expanded:
#ifdef DEBUG_ON
#define DBG
#else
#define DBG //
#endif
DBG cout << foo;
This is the simplest technique:
#ifdef DEBUG_ON
#define DBG(anything) anything
#else
#define DBG(anything) /*nothing*/
#endif
Then you can say:
//...
DBG(cout << "the value of foo is " << foo << '\n');
// ^-- `;' outside ()
Any commas in your `DBG()' statement must be enclosed in a `()':
DBG(i=3, j=4); //<---- C-preprocessor will generate error message
DBG(i=3; j=4); //<---- ok
There are also more complicated techniques that use variable argument lists,
but these are primarily useful for `printf()' style (see question on the pros
and cons of as opposed to for more).