Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RAII approach to catching constructor exceptions

I have a class that can throw an exception in its constructor. How can I declare an instance of that class in a try/catch block, while still making it available in the right scope?

try { MyClass lMyObject; }
catch (const std::exception& e) { /* Handle constructor exception */ }

lMyObject.DoSomething(); // lMyObject not in scope!

Is there an alternative way to accomplish this, while respecting the RAII idiom?

I'd prefer not to use an init() method for two-phased construction. The only other thing I could come up with was:

MyClass* lMyObject;

try { lMyObject = new MyClass(); }
catch (const std::exception& e) { /* Handle constructor exception */ }

std::shared_ptr<MyClass> lMyObjectPtr(lMyObject);
lMyObjectPtr->DoSomething();

Works OK, but I'm not happy with the raw pointer in scope and pointer indirection. Is this just another C++ wart?

like image 288
sourcenouveau Avatar asked Feb 05 '13 14:02

sourcenouveau


2 Answers

If a constructor throws that means the object failed to initialize and hence it failed to start its existence.

MyClass* lMyObject;
try { lMyObject = new MyClass(); }
catch (std::exception e) { /* Handle constructor exception */ }

In the above if the constructor throws an exception, lMyObject is left uninitialized, in other words, the pointer contains an indeterminate value.

See classic Constructor Failures for a detailed explanation:

We might summarize the C++ constructor model as follows:

Either:

(a) The constructor returns normally by reaching its end or a return statement, and the object exists.

Or:

(b) The constructor exits by emitting an exception, and the object not only does not now exist, but never existed.

There are no other possibilities.

like image 159
Maxim Egorushkin Avatar answered Nov 20 '22 21:11

Maxim Egorushkin


The best way of writing your code is this:-

MyClass lMyObject; 
lMyObject.DoSomething(); 

No trys, catches, or pointers.

If the constructor throws, then DoSomething can't get called. Which is right: If the constructor threw, then object was never constructed.

And, importantly, don't catch (or even catch/rethrow) exceptions unless you have something constructive to do with them. Let exceptions do their job and ripple up until something that knows how to handle them can do its job.

like image 32
Roddy Avatar answered Nov 20 '22 22:11

Roddy