[comp.lang.c++] Failed constructors

garry@alice.UUCP (garry hodgson) (07/18/90)

It seems to me that this discussion has gotten off track, or at least
off the track I'd hoped it would take.  The original question was,
"How do I deal with the case where a constructor fails?"  Note that
this does not necessarily mean the memory allocation failed.  Is there,
indeed, an elegant way to handle this?

An example from my own work:

I have a Connection class for doing IPC via sockets.  What I'd like to do
is something like:

	Connection *connection = new Connection( "kgbvax", PortNum );

	if ( connection )
		SendSecretDocuments( connection );
	else	ComplainLoudly();

Instead, what I do is:

	Connection *connection = new Connection( "kgbvax", PortNum );

	if ( connection->status() == GoAhead )
		SendSecretDocuments( connection );
	else	ComplainLoudly();

Admittedly, not a major difference in this example.  But conceptually,
I'd like to think that new Connection either gets me a connection to
another process, or fails in the attempt.  Having to check the state
of an object every time I create it seems rather...gasp...inelegant,
to say the least.

Anyone have a better way?

garry hodgson

PS	By the way, I think that discussing these kinds of issues, and alternate
	approaches/solutions to them, is a very effective use of this newsgroup.
	The recent discussions of C++ pros/cons have all pointed out that
	the major difficulty in effective C++ OO programming is making the paradigm
	shift to OOP.  This has also been my experience.  I find the discussion
	of "style" issues much more useful than some of the nuts & bolts stuff.
	Keep up the good work, folks.

steve@taumet.com (Stephen Clamage) (07/22/90)

garry@alice.UUCP (garry hodgson) writes:

>What I'd like to do is something like:

>	Connection *connection = new Connection( "kgbvax", PortNum );
>	if ( connection )
>		SendSecretDocuments( connection );
>	else	ComplainLoudly();

>Instead, what I do is:

>	Connection *connection = new Connection( "kgbvax", PortNum );
>	if ( connection->status() == GoAhead )
>		SendSecretDocuments( connection );
>	else	ComplainLoudly();

Sounds to me like a coding style issue.  If you really object to coding
	if ( connection->status() == GoAhead )
you could define operator() or operator! as in the streams library,
and code
	if ( (*connection)() )	// ok
or
	if ( !*connection )	// fail

In general, it would seem to be an advantage to detect the difference
between out of memory and the constructor failing for some other
reason.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

thomasw@hpcupt1.HP.COM (Thomas Wang) (07/24/90)

/ hpcupt1:comp.lang.c++ / garry@alice.UUCP (garry hodgson) /  9:08 am  Jul 18, 1990 /
>"How do I deal with the case where a constructor fails?"  Note that
>this does not necessarily mean the memory allocation failed.  Is there,
>indeed, an elegant way to handle this?

>An example from my own work:

>I have a Connection class for doing IPC via sockets.  What I'd like to do
>is something like:

>	Connection *connection = new Connection( "kgbvax", PortNum );
>	if ( connection )
>		SendSecretDocuments( connection );
>	else	ComplainLoudly();

This semantic might not be too hot.  The memory allocation success and the
connection success are independent.  Returning a null pointer will not
allow you to put in information in the object that would explain why the
connection fails.

>Instead, what I do is:

>	Connection *connection = new Connection( "kgbvax", PortNum );
>	if ( connection->status() == GoAhead )
>		SendSecretDocuments( connection );
>	else	ComplainLoudly();

I think the best solution is using an exception handling mechanism.  In the
connection constructor, the construction failure would cause an exception
to be raised.  You can put information about the failure in the exception
object.  In this case, check for good connection is not necessary.  Raising
an exception without a handler would cause the 'explaination' member function
of the exception to be invoked, then terminate the program.

This is part of my exception handling mechanism:

#define WHEREAMI __FILE__,__LINE__,me

#define RAISE(msg,type,parm) new type (WHEREAMI,msg)->fail parm
// usage:
// RAISE("", no_memory_fail_t, ());

#define protect(var) { handler_t var; if (! setjmp(var.jump_buffer))

#define catcher(var, type) else if (var.can_handle(type ::id))

#define end_protect(var) else var.abort(); }
// usage:
// protect(var)
// {
//   ... code which could cause some exception to be raised
// }
// catcher(var, no_memory_fail_t)
// {
//   ... code which recovers from out of memory failure
// }
// catcher(var, all_fail_t)
// {
//   .. code which recovers from generic failure
// }
// end_protect(var)

 -Thomas Wang
              (Everything is an object.)
                                                     wang@hpdmsjlm.cup.hp.com
                                                     thomasw@hpcupt1.cup.hp.com