Catch an exception from the constructor without hiding the object in the try block

I have a class whose constructor can throw an exception.

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

I would like to catch this exception in the client for the instance allocated on the stack. But I have to stretch the try block, at least as far as the instance should be alive.

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

Now this becomes a problem when the try block is too large to track 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 that I did not explain this problem very well: for obvious reasons, I want the try block to cover as little code as possible (i.e. just the construction).

But this creates a problem, because of which I cannot use objects after that, because they went 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); 
+7
source share
3 answers

A solution that does not 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 } 

It might be better to avoid this if possible.

+6
source

Use objects built with the heap instead of objects built on the stack so you can check which objects were created successfully, for example:

 // 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 valid for copying):

 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); 
+3
source

Another approach that may be convenient in some cases:

 class ExceptionTranslatedA : public A { public: template<typename Exc> ExceptionTranslatedA(Exc exc) try : A() {} catch (unhelpful_generic_exception) { throw exc; } }; 

This is especially useful if throwing another exception is all you wanted to do in your original try-catch block, since you can completely get rid of it. It also looks somewhat more elegant than introducing logical variables for the control flow (even if they are hidden in boost::optional s).

0
source

All Articles