是否可以对构造函数抛出异常的对象进行异常处理,该对象的异常处理接近其基于堆栈的代码创建

Can exception handling of object whose constructor throw an exception be near its stack-based creation on code?

本文关键字:异常处理 对象 于堆栈 接近 代码 堆栈 创建 构造函数 抛出异常 是否      更新时间:2023-10-16

我正在尝试使我的C++代码异常安全,并遇到了一个问题,询问朋友或搜索网络都无济于事。

根据我的理解,当使用构造函数创建对象时可能会引发异常,创建代码需要用try块括起来,异常处理是在catch(){}中完成的。

如果创建是基于堆的(例如 new使用默认分配器),我可以像这样将异常处理代码放在创建附近:

void f() {
  // work unrelated to Hoge object here
  try {
    Hoge *pHoge = new Hoge(); // could throw an exception
  } catch(HogeException& ex) {
    // handle exception
  }
  // rest of work here
}

但是,如果创建是基于堆栈的,由于块的范围,我找不到这样做的方法并求助于下面的代码try

void g() {
  // work unrelated to Hoge object here
  try {
    Hoge hoge; // could throw an exception
    // rest of work here
  } catch(HogeException& ex) {
    // handle exception
  }
}

如果上面的// rest of work代码很大,对象创建和异常处理之间的位置距离可能会很长,从而降低代码的可读性......

我更喜欢异常处理代码靠近对象创建(也许这是try - catch结构的概念之一)。有什么解决办法吗?

// rest of work委托给帮助程序函数,并将Hoge&传递给该函数:

void RestOfWork(Hoge& hoge)
{
  // rest of work here
}
void g() {
  // work unrelated to Hoge object here
  try {
    Hoge hoge;
    RestOfWork(hoge);
    // rest of work here
  } catch(HogeException& ex) {
    // handle exception
  }
}

顺便说一句,Hoge hoge();并没有做你认为它做的事情。 您可能认为您正在声明一个名为 hoge 的类型为 Hoge 的对象,并通过调用默认构造函数对其进行初始化。 您实际上正在做的是声明一个名为 hoge 的函数,该函数不带任何参数并返回Hoge by-value。 我已经在上面的代码中修复了这个问题。

编辑 事实上,正如@LightnessRacesInOrbit所建议的,Hoge对象的构造也可以在延迟函数中进行,例如:

  void RestOfWork()
  {
       Hoge hoge;
      // rest of work here
  }
  void g() {
    // work unrelated to Hoge object here
    try {
      RestOfWork();
    } catch(HogeException& ex) {
      // handle exception
    }
  }

执行此操作的合理方法是使用可为空的单项容器,例如 boost::optional

void g() {
  // work unrelated to Hoge object here
  boost::optional<Hoge> opt_hoge;
  try {
    opt_hoge = boost::in_place<Hoge>();
  } catch(HogeException& ex) {
    // handle exception
  }
  Hoge &hoge = *opt_hoge;
  // rest of work here
}

如果您不能使用 Boost,std::unique_ptr将以堆分配为代价:

void g() {
  // work unrelated to Hoge object here
  std::unique_ptr<Hoge> opt_hoge;
  try {
    opt_hoge = std::unique_ptr<Hoge>(new Hoge);
  } catch(HogeException& ex) {
    // handle exception
  }
  Hoge &hoge = *opt_hoge;
  // rest of work here
}