使用异常时,C ++代码变为非线性

时间:2015-05-28 12:55:56

标签: c++ exception raii

我的项目主要看起来像

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并保持代码清晰?

3 个答案:

答案 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 ++良好实践而言,它不是那么干净和安全,因为用户可能忘记检查它是否有效,但选项就在那里。