我的项目主要看起来像
Object a;
if (! a.initialize(x, y, z))
return EXIT_FAILURE;
// 100 lines using a
a.finalize();
我试图改变这部分代码并使用RAII idiome。
所以,我删除了initialize
函数和finalize
并在构造函数和析构函数中移动代码。
为了捕获initialize()
错误,如果出现错误,我会在构造函数中抛出异常。
现在,我的代码是这样的:
try
{
Object a(x, y, z);
// 100 lines using a
} catch (my_exception&)
{
return EXIT_FAILURE;
}
认为麻烦的是100行代码。我的try
太长,只有一个错误。我有多个对象,如a
。
所以在我的代码是线性的之前:
Object a;
if (! a.initialize(x, y, z))
return EXIT_FAILURE;
Object b;
Object c;
if (!b.initialize() || !c.initialize())
return EXIT_FAILURE;
a.finalize();
现在看起来丑陋,难以阅读:
try
{
Object a(x, y, z);
try
{
Object b;
try
{
Object c;
}
catch (my_exception_c&)
{
return EXIT_FAILURE;
}
}
catch (my_exception_b&)
{
return EXIT_FAILURE;
}
} catch (my_exception&)
{
return EXIT_FAILURE;
}
如何使用RAII并保持代码清晰?
答案 0 :(得分:5)
通常,在要处理异常的级别创建一个try块。在这种情况下,您只需要在任何异常后清理顶级块:
try {
Object a(x, y, z);
Object b;
Object c;
// code using these
} catch (...) {
// end the program if any exception hasn't been handled
return EXIT_FAILURE;
}
现在它没有#34;太长时间没有一个错误&#34 ;;对于可能发生的任何错误,它的长度是正确的。
将自己局限于源自std::exception
的异常是个好主意;那么你可以在没有处理的情况下给出一些可能有用的信息:
catch (std::exception const & ex) {
std::cerr << "ERROR: " << ex.what() << std::endl;
return EXIT_FAILURE;
}
答案 1 :(得分:1)
你只需要一个这样的捕获:
int main()
(&#39; ......&#39;字面意思是&#39; ...&#39;)
这样,您将在同一个catch中捕获ObjectA和ObjectB等的所有exeptions。因此,如果您制作自定义异常,最好在其中添加一些信息。
答案 2 :(得分:1)
您可以随时使用其他功能,例如&#34; IsValid()&#34;在调用构造函数后检查而不是抛出异常。您可以保留RAII的优势(异常安全,防止初始化/破坏错误,......)但您可以使代码保持与以前相同的格式。 就C ++良好实践而言,它不是那么干净和安全,因为用户可能忘记检查它是否有效,但选项就在那里。