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

C++ code became no-linear when using exception

我的项目主要是这样的

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

一般来说,在你想要处理异常的级别创建一个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;
}

现在不是"too long for one error";对于可能发生的任何错误,它都是正确的长度。

将自己限制在从 std::exception 派生的异常中是个好主意;那么你可以在未处理的情况下提供一些可能有用的信息:

catch (std::exception const & ex) {
    std::cerr << "ERROR: " << ex.what() << std::endl;
    return EXIT_FAILURE;
}

你只需要一个这样的捕获物:

try
{
  Object a;
  Object b;
  //100 lines of code
}
catch(ExeptionA& exa)
{
  cerr << "error a" << endl;
}
catch(ExeptionB& exa)
{
  cerr << "error B" << endl;
}
catch(...){
  cerr << "some other error" << endl;
}

(“...”的字面意思是“...”)

这样,您将在同一捕获中捕获来自 ObjectA 和 ObjectB 等的所有异常。因此,如果您创建自定义异常,最好在它的来源处添加一些信息。

你总是可以有另一个像 "IsValid()" 这样的函数,你可以在调用构造函数后检查它而不是抛出异常。您保留了 RAII 的好处(异常安全、针对 initialization/destruction 错误的保护,...),但您将能够使您的代码保持与以前相同的格式。 就 C++ 良好实践而言,它不是那么干净和安全,因为用户可能会忘记检查它是否有效,但选项就在那里。