Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catch Exception from constructor without hiding the object in the try block

Tags:

c++

exception

I have a class whose constructor might throw an exception.

class A {
    A() { /* throw exception under certain circumstances */ }
};

I would like to catch this exception in the client for a stack-allocated instance. But I find myself forced to extend the try block at least as far as the instance must be alive.

try {
    A a;
    do_something(a);
} catch {
    // ...
}

Now this obviously becomes a problem when the try block is too large to track down the source of the exception:

try {
    A a1;
    A a2;
    do_something(a1, a2);
} catch {
    // Who caused the exception?
}

What would I do to avoid the situation?

UPDATE:

It seems I hadn't explained the problem very well: For obvious reasons, I want to have the try block spanning as little code as necessary (that is, only the construction).

But that creates the problem that I can't use the objects afterwards because they have moved out of scope.

try {
    A a1;
} catch {
    // handle a1 constructor exception
}
try {
    A a2;
} catch {
    // handle a2 constructor exception
}

// not possible
do_something(a1, a2);
like image 295
Jo So Avatar asked Jan 07 '13 21:01

Jo So


2 Answers

A solution that doesn't require changing A is to use nested try/catch blocks:

try {
    A a1;
    try {
        A a2;
        do_something(a1, a2);
    }
    catch {
      // a2 (or do_something) threw
    }
} catch {
    // a1 threw
}

Probably better to avoid doing this if possible though.

like image 93
Pubby Avatar answered Oct 27 '22 12:10

Pubby


Use heap-constructed objects instead of stack-constructed objects, so that you can test which objects have been constructed successfully, eg:

// or std::unique_ptr in C++11, or boost::unique_ptr ...
std::auto_ptr<A> a1_ptr;
std::auto_ptr<A> a2_ptr;

A *a1 = NULL;
A *a2 = NULL;

try
{
    a1 = new A;
    a1_ptr.reset(a1);
}
catch (...)
{
}

try
{
    a2 = new A;
    a2_ptr.reset(a2);
}
catch (...)
{
}

if( (a1) && (a2) )
    do_something(*a1, *a2);

Alternatively (only if A is copy-constructible):

boost::optional<A> a1;
boost::optional<A> a2;

try
{
    a1 = boost::in_place<A>();
    a2 = boost::in_place<A>();
}
catch (...)
{
    //...
}

if( (a1) && (a2) )
    do_something(*a1, *a2);
like image 32
Remy Lebeau Avatar answered Oct 27 '22 11:10

Remy Lebeau