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

C++ C++;使用异常时,代码变得非线性,c++,exception,raii,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()错误,如果有什么失败,我会在构造函数中抛出一个异常 现在,我的代码是这样的: t

我有一个项目,它的主体看起来是这样的

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;
}
现在它不是“一个错误的时间太长”;对于可能发生的任何错误,它都是正确的长度

最好将自己限制为从
std::exception
派生的异常;然后,您可以在未处理的情况下提供一些潜在有用的信息:

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

std::cerr通常,在您想要处理异常的级别创建一个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;
}
现在,它不是“对于一个错误来说太长”,而是对于任何可能发生的错误来说都是正确的长度

最好将自己限制为从
std::exception
派生的异常;然后在未处理的情况下,您可以提供一些潜在有用的信息:

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

std::cerr您只需要一个这样的捕获:

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;
}
试试看
{
对象a;
对象b;
//100行代码
}
捕获(例外a和exa)
{

cerr您只需要一次这样的捕获:

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;
}
试试看
{
对象a;
对象b;
//100行代码
}
捕获(例外a和exa)
{

cerr您可以始终拥有另一个函数,如“IsValid()”,在调用构造函数后进行检查,而不是抛出异常。您可以保留RAII(异常安全、防止初始化/销毁错误等)的优点,但您可以使代码保持与以前相同的格式。
在C++的好实践中,它不是干净和安全的,因为用户可以忘记检查它是否有效,但是选项是存在的。

你总是可以有一个函数,比如“ISUVE()”,在调用构造函数之后检查,而不是抛出异常。(异常安全、防止初始化/销毁错误等),但您将能够保持代码的格式与以前相同。
对于C++的好实践来说,它不是干净和安全的,因为用户可以忘记检查它是否有效,但是选项是存在的。

非纯RAII是一个CBOTS可以在不抛出的情况下失败的原因,RAII对象记录了这样的失败。它看起来像是两个例子的混合,但是资源清理在返回错误子句中是自动的。非纯RAII是一种CTOR可以在不抛出的情况下失败的方法,RAII对象记录了这种失败。它看起来像是两个示例的混合体,但在return error子句中,资源清理是自动的。