RAII and exception in constructor

Imagine that I have a job that can be done in three ways: slow and painful, but fail-safe; a path with moderate suffering, if you have Resource1 ; and a quick and easy way that requires both Resource1 and Resource2 . These resources are now valuable, so I ResNHolder them up in a RAII implementation of ResNHolder and write something like this:

 void DoTheJob(Logger& log/*, some other params */) { try { Res1Holder r1(/* arguments for creating resource #1 */); try { Res2Holder r2(/* arguments */); DoTheJobQuicklyAndEasily(log, r1, r2); } catch (Res2InitializationException& e) { log.log("Can't obtain resource 2, that'll slowdown us a bit"); DoTheJobWithModerateSuffering(log, r1); } } catch (Res1InitializationException& e) { log.log("Can't obtain resource 1, using fallback"); DoTheJobTheSlowAndPainfulWay(log); } } 

"DoTheJobXxx ()" refers to Logger / ResNHolder because they are not copied. Am I doing it too awkwardly? Is there another smart way to structure a function?

+7
c ++ exception raii
source share
2 answers

I think your code will be fine, but here is an alternative to consider:

 void DoTheJob(Logger &log/*,args*/) { std::unique_ptr<Res1Holder> r1 = acquireRes1(/*args*/); if (!r1) { log.log("Can't acquire resource 1, using fallback"); DoTheJobTheSlowAndPainfulWay(log); return; } std::unique_ptr<Res2Holder> r2 = acquireRes2(/*args*/); if (!r2) { log.log("Can't acquire resource 2, that'll slow us down a bit."); DoTheJobWithModerateSuffering(log,*r1); return; } DoTheJobQuicklyAndEasily(log,*r1,*r2); } 

If getsRes functions return null unique_ptr when the resource is not initialized:

 std::unique_ptr<Res1Holder> acquireRes1() { try { return std::unique_ptr<Res1Holder>(new Res1Holder()); } catch (Res1InitializationException& e) { return std::unique_ptr<Res1Holder>(); } } std::unique_ptr<Res2Holder> acquireRes2() { try { return std::unique_ptr<Res2Holder>(new Res2Holder()); } catch (Res2InitializationException& e) { return std::unique_ptr<Res2Holder>(); } } 
+2
source share

The code looks good, the only problem I can imagine, maybe with execution, since the exception is considered not very efficient. If so, you can change the code to:

 void DoTheJob(Logger& log/*, some other params */) { Res1HolderNoThrow r1(/* arguments for creating resource #1 */); if( r1 ) { Res2HolderNoThrow r2(/* arguments */); if( r2 ) DoTheJobQuicklyAndEasily(log, r1, r2); else { log.log("Can't obtain resource 2, that'll slowdown us a bit"); DoTheJobWithModerateSuffering(log, r1); } } else { log.log("Can't obtain resource 1, using fallback"); DoTheJobTheSlowAndPainfulWay(log); } } 

You will need another RAII object that does not throw an exception, but has a state and returns it in operator bool () or somewhere else. But your code looks less error prone, and I would prefer to use it if you don't have a performance problem or you need to avoid exceptions.

+1
source share

All Articles