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

时间:2012-11-23 13:42:22

标签: c++ exception-handling

我正在尝试使我的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结构的概念之一)。有没有解决方案?

2 个答案:

答案 0 :(得分:5)

// 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的{​​{1}}类型的对象,并通过调用默认构造函数对其进行初始化。你实际在做的是声明一个名为Hoge的函数,该函数不带参数并返回hoge个值。我在上面的代码中解决了这个问题。

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

Hoge

答案 1 :(得分:0)

合理的方法是使用可以为空的单项容器,例如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
}