RAII和构造函数中的异常
想象一下,我有一份工作要做,可以通过三种不同的方式完成:一种缓慢而痛苦的方式,但是失败的方式; 考虑到你有Resource1
; 和一个快速简单的方法,这需要Resource1
和Resource2
。 现在,这些资源是非常宝贵的,所以我把它们包装到RAII中,实现ResNHolder
并写下如下内容:
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函数返回一个空的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>();
}
}
你的代码看起来很好,我可以想象你可能会遇到的唯一问题是性能,因为异常被认为不是很有效。 如果是这样,您可以将代码更改为:
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);
}
}
您将需要另一个RAII对象,它不会抛出异常但具有状态并将其返回到运算符bool()或其他位置。 但是你的代码看起来对我来说更不容易出错,我宁可使用它,除非你有性能问题或需要避免异常。
链接地址: http://www.djcxy.com/p/16131.html