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