Archived

This topic is now archived and is closed to further replies.

AndreTheGiant

How handle Errors in Constructor?

Recommended Posts

AndreTheGiant    329
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?

Share this post


Link to post
Share on other sites
Igilima    122
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]

Share this post


Link to post
Share on other sites
himh    122
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!

Share this post


Link to post
Share on other sites
BitMaster    8651
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.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
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.

Share this post


Link to post
Share on other sites
pinacolada    834
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.

Share this post


Link to post
Share on other sites
daerid    354
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 something

if(!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

Share this post


Link to post
Share on other sites
_the_phantom_    11250
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.

Share this post


Link to post
Share on other sites
daerid    354
I personally have to agree. Exceptions are by far the cleanest and most elegant (and headache free) method of dealing with errors in the Ctor. Take a look at the various boost libraries, which definitely make use of exceptions in ctors.


daerid | Legends | Garage Games | Spirit | Hapy | Boost | Python | Google
"Doomed to crumble, unless we grow, and strengthen our communication" - Maynard James Keenan, Tool

Share this post


Link to post
Share on other sites
George2    187
Exceptions are good but :



class A
{
int* fluffy;
public:
A() : fluffy(0)
{
fluffy = new int[100];
throw Exception();
}

~A()
{
delete [] fluffy;
}
};

int main()
{
try
{
A foo;
}
catch (...)
{
}
}


Does foo''s destructor get called ?

Share this post


Link to post
Share on other sites
biovenger    122
Yes, it gets called when A goes out of focus just as with every variable. The tricky thing is if you do this:


void somefunction()
{
A *ptr = new A;

if(A.AnyErrorOccured())
throw(alloc_exception("Initialization of A failed");
}


Now, what happens here is that the stack gets unwinded back to the try block and the program goes into the corresponding catch block. The problem here is that the pointer 'ptr' was a local variable and thus it value dissapears from the stack as soon as somefunction threw an exception. Which means you have lost a pointer which results in a memory leak.

Although the above problem has nothing to do with exceptions. If you only did a return code instead of an exception the same problem would arise, ptr would dissapear from the stack and you have a memory leak.

Edit: I also agree with the person who thought that exceptions were mentioned too late in this post. Although, one must know the difference between using exceptions and over-using exceptions. Many things are best left to normal return codes, error collection functions or pure 'exit(0)'. While exceptions are exceptionally (dry programmer humour) good when used correctly a big problem with many new programmers is that they overuse exceptions and thus create an unneccecarily complex program.

[edited by - biovenger on January 8, 2004 11:06:47 AM]

Share this post


Link to post
Share on other sites
SiCrane    11839
quote:
Original post by George2
Exceptions are good but :



class A
{
int* fluffy;
public:
A() : fluffy(0)
{
fluffy = new int[100];
throw Exception();
}

~A()
{
delete [] fluffy;
}
};

int main()
{
try
{
A foo;
}
catch (...)
{
}
}


Does foo''s destructor get called ?



No. foo''s destructor won''t get called. Any object who''s constructor throws an exception will not get destroyed. However, if it has a base class and the exception didn''t occur in the base class''s constructor, the base class''s destructor will be called. Similarly, if it has member variables that are of class type, then their destructors will be called.

In this case foo.fluffy''s memory will leak.

Share this post


Link to post
Share on other sites
Leathrewulfe    122
While I agree that an exception is probably your best bet in this case, but I wouldn''t get in the mindset that throwing exceptions are always a viable alternative to int returns. Exceptions are expensive compared to the alternative.

Share this post


Link to post
Share on other sites
DrPizza    160
quote:
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.



No, you don''t want to do that, because it''s error-prone and stupid.

To handle an error in the constructor you throw an exception. Obviously.

Share this post


Link to post
Share on other sites
DrPizza    160
quote:
The "zombie" thing mentioned is how the std library does it (at least the iostream part).

It''s just about tolerable for fstreams, as a file not found is (arguably) a reasonable event to occur when opening a file -- but that doesn''t seem to me to justify such an approach in general. Even then, I tend to make the stream throw on badbit and failbit.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
quote:
Original post by SiCrane
quote:
Original post by George2
Exceptions are good but :



class A
{
int* fluffy;
public:
A() : fluffy(0)
{
fluffy = new int[100];
throw Exception();
}

~A()
{
delete [] fluffy;
}
};

int main()
{
try
{
A foo;
}
catch (...)
{
}
}


Does foo''s destructor get called ?



No. foo''s destructor won''t get called. Any object who''s constructor throws an exception will not get destroyed. However, if it has a base class and the exception didn''t occur in the base class''s constructor, the base class''s destructor will be called. Similarly, if it has member variables that are of class type, then their destructors will be called.

In this case foo.fluffy''s memory will leak.


Yes, however it''s worth remembering that when an exception is thrown in a constructor the partially constructed object is destroyed to the extent that it has been constructed. If you used an std::vector<int> instead of a int* then the vector''s destructor would be called and normal RAII principles apply.

The argument that you shouldn''t throw exceptions from constructors because calling functions might not catch the exception is bogus, somewhere down the line the code that might fail will be called and the calling code would have to be prepared for it, better to use constructors to create and invariant than to leave the possibility of invalid objects being used.

The point about if(!file) doesn''t hold, the ! operator on file objects might return true for a variety of reasons, not all of which should be considered exceptional (file::close() doesn''t have to throw an error every time it''s called!).

Share this post


Link to post
Share on other sites
emileej    130
Might as well throw in my poinion too.
Init functions will do the job but sooner or later it will come back and punch you right on the nose. You will have to check, in all the functions using data created in the init, if init has been called or youre in big trouble. Or you could just say "to hell with it" and pray that you remember not to use the above mentioned functions before the init call.
Now throwing an exception is a whole other story. The class will scream at you if something goes wrong and if you remember to destroy any data you might have created in the constructor up untill the exception was thrown - youre home free.

"Stop trying to hit me and hit me!"
[Edit]That dammed AP said my point about destroying data created in the constructor [/Edit]

[edited by - emileej on January 8, 2004 12:26:12 PM]

Share this post


Link to post
Share on other sites
daerid    354
The whole freakin point of constructors is so that when the constructor finishes, you have an object that''s in a valid, useable state (to one degree or another). Separating that logic out into an Init() function is just sloppy coding, and defeats the purpose of one of the main C++ design concepts.


daerid | Legends | Garage Games | Spirit | Hapy | Boost | Python | Google
"Doomed to crumble, unless we grow, and strengthen our communication" - Maynard James Keenan, Tool

Share this post


Link to post
Share on other sites
_the_phantom_    11250
it probably stems from the fact that exceptions are slow and that everyone wants their code to be lightning fast when infact at setup time its probably better to kill a bit of speed and make sure your objects are created in a sane state

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
quote:
Original post by _the_phantom_
it probably stems from the fact that exceptions are slow and that everyone wants their code to be lightning fast when infact at setup time its probably better to kill a bit of speed and make sure your objects are created in a sane state


The costs of exceptions are seriously over-estimated. In fact code that uses exceptions consistently as the basis of it''s error-handling strategies tends to be more efficient; in particular use of exceptions tends to optimise towards the non-exceptional code path, which tends to be the one most often taken.

Share this post


Link to post
Share on other sites
fizban75    130
Best Practices summary for class constructors:

1) Use RAII (Resource Acquisition Is Initialization). This is a fundamental element of good object-oriented software development. When you construct an object, it should also be completely initialized and ready to rock and roll. If you have different ways of initializing an object, have multiple constructors.

2) If something fails to initialize in the constructor, one of two things should happen. If the object can be considered as usable even with the failure, then continue on normally and just make sure the class can handle things even though it doesn''t have that resource. On the other hand, if failure to acquire a resource means that the object is not usable, throw an exception. That''s what they''re there for.

3) If you throw an exception in the constructor and have already acquired some resources before throwing the exception, you must free those resources before throwing. When you throw an exception in a class constructor, the object is not considered valid and therefore the destructor will not be called.

Hope that helps.

Share this post


Link to post
Share on other sites