From: matt@centerline.com (Matt Landau)
Subject: Re: Return value for the constructors.
Organization: CenterLine Software, Inc.
Distribution: usa
Date: Fri, 21 Aug 1992 14:39:36 GMT

In <2284@devnull.mpd.tandem.com> rgp@mpd.tandem.com (Ramon Pantin) writes:
>So, to get an error code out of a constructor we should (note that I
>DON'T agree with all this!):
>
>- Forbid the creation of automatic variables and arrays, i.e. make
>  the constructors non-public.
>
>- Do the new/constructor thing.
>
>- Have some public static member function that creates objects.
>
>Sounds pretty convuluted, don't you think?
>No wonder nobody seems to write simple code anymore!

Well, as the person who pointed out how one can make constructors private,
let me hasten to add that I don't actually recommend this approach; I was
just pointing out that it *is* possible.

In addition to the "forbid automatic objects and overload operator new"
approach, there are two other things one can do about constructor failures
in a C++ environment that lacks exceptions:

(1)  Have an "isValid" bit in every object, which the constructor sets
     or clears before returning.  Application code is then responsible 
     for testing "obj.isValid" before using any object.  I know of a 
     couple of different class libraries that have taken this approach.
     The penalty for not testing the isValid bit is using a potentially 
     uninitialized or invalid object.

(2)  Try very hard to write constructors that cannot fail, and move any
     failure-prone initialization (like dynamic allocation) to some 
     secondary initialization routine.  Application code then becomes 
     responsible for calling "obj.Init()" before using any object.  The 
     penalty for omitting the call is using a potentially uninitialized 
     or invalid object.

     You can sort of get around this problem if you can make sure the
     Init member function requires no arguments (so it can be called 
     from anywhere within the class's own implementation), keep an 
     isInitialized bit in the object, have EVERY member function of 
     the object test isInitialized and call Init if needed, and forbid 
     the use of public data members, escshewing them in favor of inline
     member functions of the form:

	inline int X::Count(void) const
	{
	    if (!isInitialized) Init();
	    return _count;
	}

     Of course, this approach is also a big kludge, inconvenient to 
     maintain, and subject to code size explosion if you have a large
     number of short member functions.

The fact that both of these approaches leave you with the potential for
using an incompletely initialized object (the very thing constructors in
C++ were supposed to prevent!) points to a basic shortcoming in most of
the current implementations of the language.  

The underlying point is that without a decent exception system, there 
is **NO** good way to deal with the problem of constructor failures.  
There are several different not-so-good ways to choose from; which one 
you choose depends on the nature of the system you're writing.

Even *with* a decent exception system, the problem doesn't just go away.
Exceptions provide a mechanism and a framework within which one can deal
with this problem (as well as many other problems).  The design skills
and engineering discipline needed to use exceptions both correctly and 
robustly are still not to be underestimated.
--
 Matt Landau			Waiting for a flash of enlightenment
 matt@centerline.com			  in all this blood and thunder
Newsgroups: comp.lang.c++