想象一下,我有一份工作要做,可以通过三种不同的方式来完成:缓慢而痛苦,但却是安全的方式;鉴于你有资源1,适度痛苦的方式;以及一种快速简便的方法,它需要Resource1和Resource2.现在,这些资源是宝贵的,所以我将它们包装成RAII实现ResNHolders并写下这样的东西:
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()”引用了Logger / ResNHolder,因为它们是不可复制的.我这样做太笨拙了吗?有没有其他聪明的方法来构建函数?
解决方法
我认为你的代码会很好,但这里有一个可以考虑的替代方案:
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); }
当资源无法初始化时,acquireRes函数返回null unique_ptr:
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>(); } }