Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't constructors gracefully handle errors?

I read the following

The inability to gracefully handle errors in C++ constructors is one good reason to avoid constructors that do more than nothing, and use initialization functions instead. And C++ exceptions are not a graceful way to handle errors, especially in constructors. If your member object constructor throws an exception, and you want to catch it in your constructor, the normally ugly colon syntax gets much uglier.

I would like to know why constructors can't gracefully handle errors ? Constructors can still support try-catch so why is it that constructors can't gracefully handle errors ?

like image 964
Rajeshwar Avatar asked Mar 14 '14 17:03

Rajeshwar


People also ask

How do constructors handle errors?

Basically, there are two steps: First, allocate raw memory for the object. Second, call the constructor in that memory, creating the object. If the second step throws an exception, enter stack unwinding. Else schedule the destructor call.

How do you handle exception if it comes in calling of constructor?

When throwing an exception in a constructor, the memory for the object itself has already been allocated by the time the constructor is called. So, the compiler will automatically deallocate the memory occupied by the object after the exception is thrown.

Why exception handling is an effective means for dealing with constructor failure?

Explain why exception handling is an effective means for dealing with constructor failure. ANS: A thrown exception passes to the outside world the information about the failed constructor and the responsibility to deal with the failure.

Can constructor throw error?

The short answer to the question “can a constructor throw an exception in Java” is yes! Of course, properly implementing exceptions in your constructors is essential to getting the best results and optimizing your code.


2 Answers

I would like to know why constructors cant gracefully handle errors ?

They can, by throwing an exception if initialisation fails.

This is far more "graceful" than the suggestion to leave the object in a half-alive state, to be properly initialised by calling a function later. Used correctly[1], exceptions guarantee that the object is either fully initialised, or doesn't exist.

This advice presumably comes from someone who disapproves of the use of exceptions to report error conditions; in which case C++ does indeed become an extremely clumsy language, with no convenient way to express initialisation failure. Fortunately, the use of exceptions is idiomatic among most C++ programmers, so there's usually no need to pay attention to this kind of nonsense.

[1] Specifically, in conjunction with RAII, to avoid the need to "catch it in your constructor" or anywhere apart from the error handler itself.

like image 178
Mike Seymour Avatar answered Sep 30 '22 18:09

Mike Seymour


I think "gracefully handling errors" is subjective...

Anyway, probably the author is thinking of something like:

class X
{
private:
   int * v1; // a vector of int's, dynamically allocated
   int * v2; // another vector of int's, dynamically allocated

public:
    X() 
    {
        v1 = new int[...];
        .... do something

        v2 = new int[...];
        ... If this throws, then v1 is leaked, since destructor is not called for X

        ...
    }
};

Actually, I think that if you proper use RAII and RAII building-blocks, there are no problems, and constructor can handle errors gracefully (for some meaning of "gracefully").

In the above example, if you replace the raw dynamically-allocated arrays with a RAII building-block like std::vector, you have no problems, since destructors are called on data members if an exception is thrown in the constructor of class X (even if the destructor for X is not called):

class X
{
private:
   std::vector<int> v1;
   std::vector<int> v2;

public:
    X() 
    {
        v1.resize(...);
        .... do something

        v2.resize(...);
        // If this throws, then v1 is NOT leaked, 
        // since the destructor is called for v1 data member

        ...
    }
};

Anyway, there are cases in which you just don't want the constructor to throw, e.g. a file class, in which you can have an IsOpen() member function to check if the file was opened successfully in the constructor (instead of having the constructor throwing an exception if file open fails).
This is just a matter of personal design preference.

like image 32
Mr.C64 Avatar answered Sep 30 '22 17:09

Mr.C64