How handle Errors in Constructor?

Started by
40 comments, last by AndreTheGiant 20 years, 3 months ago
I feel dumb asking this because I should know the answer already. What is a good thing to do when your constructor encounters an error, for example a file could not be found? You obviously can''t return an error code like 0 or 1 and have the calling code check it, since constructors dont return anything. I guess you could pawn the potentially error-prone code off to a helper function, but that only delays the problem. For example:

Ctr() {
  if ( !loadFile("reaaaadme.txt") ) {
     // same problem here. what do you do with this error?

  }
}
Then of couse, there is exceptions with try and catch and all that. How does this work? If you throw and exception in the constructor, where do you catch it? Do you have have code in the catch that undoes any resource allocation that you did in the constructor before the error occured? What is the best thing to do?
Advertisement
Usually you don't want to do anything that can fail in the constructor. Instead you call .Init() on your object right after constructing it in order to do anything that can fail. That way you can return an error message.

Otherwise, your other options are to try to do some sort of recovery within the constructor (create the file since it doesn't exist?) or leave the file pointer set to NULL and check it later before using it. If the code that uses the filepointer later finds that it is NULL then that code can return the error.

One other way that I just thought of is to pass the address of a variable, put your constructor's return into that and check its contents after constructing the object.

CMyObject::CMyObject(BOOL* pFailed)
{
if ( !loadFile("reaaaadme.txt") )
{ // same problem here. what do you do with this error?
*pFailed = TRUE;
}
}

BOOL bFailed = FALSE;
pMyObject = new CMyObject(&bFailed);
if(bFailed)
{
// Oh no, something failed in my object's constructor
}

[edited by - Igilima on January 7, 2004 5:32:42 PM]
Don''t put any code in a constructor that can fail. Most reasons to put code in a constructor that can fail are for clean looking code. Unfortunately, most don''t put the parallel error handling code necessary outside the constructor (let alone anywhere else). If they did, they wouldn''t like the appearance and re-design the constructor. Keep your constructors thin and light. You never know when someone is going derive from them. And so on.

Happing Coding!
Three options:

1) Don''t do anything in a constructor that can fail.

2) Include an checkError() member function like the C++ stream classes have and which must be called and checked after construction/method calls.

3) Throw an exception from the constructor. This is a clean way for serious problems.
Have you guys never heard of RAII?! Of course it is OK to put code in a constructor that can possibly fail! This is what exceptions are for. Exceptions are like error codes that come with their own descriptions (there is more to it than that, but let''s just compare it to the old C style of return codes). Instead of returning -1 for this error 3 for that error, you throw an exception. You can throw an exception from your constructor on failure and the caller can catch the exception and deal with it. Having to call a separate Init() function is redundant and ugly.
So what is RAII? Its obvious that you think it is good. Could you explain quickly?
Click and learn.
-----------------------------Final Frontier Trader
Another thing you can do is make it possible for the object to go into a "zombie" or "error" state. So, the contructor doesn''t throw exceptions or anything, it pretends that everything is fine, but if it encounters an error, it goes into the zombie state. Then maybe the function has a getError() function, and it''s the owner''s job to call getError() to find out if anything went wrong. And, write all the functions of the object so that if it is in a zombie state, it still won''t cause an error (although it surely won''t do anything useful either).

But personally, I prefer writing an init function. This also avoids the whole construction order fiasco.
The "zombie" thing mentioned is how the std library does it (at least the iostream part).

#include <fstream>using namespace std;ifstream file("somefile.txt");// if somefile.txt doesn''t exist, do somethingif(!file){  // toss an error or otherwise handle}else{  // file is good use and close  file.close();}


daerid | Legends | Garage Games | Spirit | Hapy | Boost | Python | Google
"Doomed to crumble, unless we grow, and strengthen our communication" - Maynard James Keenan, Tool
daerid@gmail.com
I''ma touch worried that it took 3 posts for someone to mention exceptions.
As soon as a read the topic title its what i thought of right away, its the natural way to handle the problem where you need to signal an error without a return value.
With file opening and the STL zombie states make sense (and i''m sure the clever ppl who designed it can rest easy now i''ve agreed, heeh) but I''d say for most other critical (sp?) errors where normal operation can not be continued an exception is the best option.

This topic is closed to new replies.

Advertisement