构造函数中的 RAII 和异常
RAII and exception in constructor
想象一下,我有一份工作要做,可以通过三种不同的方式完成:一种缓慢而痛苦但万无一失的方式;一种是适度痛苦的方式,因为你有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() 或其他位置返回它。但是你的代码对我来说看起来不太容易出错,我宁愿使用它,除非你有性能问题或需要避免异常。
相关文章:
- 具有瞬态资源的RAII类
- 处理多个异常集合的C++方法
- 我在c++代码中生成了一个运行时#3异常
- 孤立代码块在结构中引发异常
- C++中的赋值发生,尽管右侧出现异常
- 从构造函数抛出异常时如何克服内存泄漏
- 异常属于C++中的线程还是进程
- 当类定义不可见时捕获异常
- 引发异常:读取访问冲突**dynamicArray**为0x1118235.发生
- 为什么异常不退出程序?
- 为什么我应该在异常处理中使用std::cerr而不是std::cout
- 如何修复链表类实现的未处理异常0xDDDDDDDD
- 关于:C++中异常对象的范围:为什么我没有得到副本?
- 是什么导致了Unity 3D中的"错误线程异常"?
- 为什么我们需要 RAII 来解决异常安全问题
- 使用RAII嵌套异常
- 构造函数中的 RAII 和异常
- 从 RAII 类的析构函数引发异常
- c++ RAII析构函数异常
- 捕获构造函数异常的RAII方法