Design Issues Supported By CLASSGEN
As stated in the article, I intended that CLASSGEN function as a repository of design experience. One way CLASSGEN does this is by forcing you to decide whether or not to include certain features in your class. I list these features as follows:
Copy Constructor and Assignment Operator
CLASSGEN urges you to make up your mind about the copy constructor and assignment operator issue. If you choose to define them, CLASSGEN will generate these functions' prototypes and empty bodies for you (with a ready-made test for assignment to self in operator=). If you choose "Default," CLASSGEN will let the compiler generate its shallow, memberwise copy functions. If you do not want these functions at all, CLASSGEN will generate two private prototypes and no body, so that either the compiler or the linker will complain if someone calls them. Scott Meyer's book, Effective C++ [1] contains a thorough discussion of the copy constructor and assignment operator.
Inheritance
CLASSGEN expects you to decide from the very beginning whether your new class is meant to be derived somewhere down the line. If it is, check the "Virtual destructor" box in the user interface. Selecting a virtual destructor will ensure that the appropriate derived-class destructor gets called in polymorphic code. If your class is not inherited, do not ask CLASSGEN for a virtual destructor "just in case," especially if your class has no other virtual functions, unless you want all your objects to house a pointer to a useless vtable (again, see [1] for a thorough explanation). Oddly enough, the only difference between the two in generated source is the keyword virtual in the destructor's prototype. I decided to make this feature a part of CLASSGEN because I experienced hours of random general protection faults last time the keyword was missing.
Class-Specific new Handler
Checking this option will cause CLASSGEN to add three lines of code to create a class-specific new handler. The new handler rings a CLASS-specific bell if memory allocation fails while attempting to create a new class instance. To set up the handler, the generated code calls standard function set_new_handler, which establishes a static member function CLASS: :NoMemory as the handler. After memory is successfully allocated, the old handler is restored. [1] shows a somewhat more complicated way of doing it.
Instance Count
This is a feature that might prove useful in actual design (to build a singleton, for example), as well as in debug stages. If the instance count drops to zero in the class invariant, your destructor has been called one too many times. You might also want to display its value when out of memory.
Emdedded CRC
I decided to throw in this firewall against wild pointers after hours of fighting with an obscure ISDN programming interface. Basically, the class invariant peforms a checksum at memory address this, over a length sizeof(*this), and blows the whistle if the result doesn't match the expected value. Obviously, you should call the private method for updating this value at the end of all your non-const member functions. You should also call the class invariant at the beginning of all member functions. Since CLASSGEN generates code for altering the CRC value in the destructor, this option will also protect against using references to already destroyed objects. As for uninitialized objects, it is highly unlikely that a garbage value matches the computed CRC of the surrounding garbage zone. Since this kind of check adds a heavy run-time overhead, it all recompiles to nothing when NDEBUG is defined. (You might want to do the same thing whenever you add code meant for debugging and/or profiling to the pattern files.)