在成员变量初始化期间有条件地处理异常

时间:2014-09-25 15:29:49

标签: c++ exception-handling

好的StackOverflow民谣。

有没有更好的方法来处理成员变量构造函数中的异常?我不得不与一个库类进行交互,这个类可能会也可能不会在它的构造函数中抛出异常(无法提前检查)并且我想避免在我的类中使用指针(如果发生了崩溃) ,我希望所有析构函数都被正确调用,即使我搞砸了)。我目前已经确定了这个实现(例如,包括一个虚拟存根):

class class_I_have_no_control_over{
  public:
    class_I_have_no_control_over( int someArgument )
    {
        if( someInternalConditionThatCantBeTestedExternally )
            throw anException;
    }

    class_I_have_no_control_over( )
    { //Does not throw
    }
}

class MyClass{
  private:
    class_I_have_no_control_over memberVariable;

  public:
    MyClass()
    {
        try{
            class_I_have_no_control_over tempVariable( 24 );
            memberVariable = std::move( tempVariable );
        }catch(...)
        {
            class_I_have_no_control_over tempVariable( );
            memberVariable = std::move( tempVariable );
        }
    }
}

我考虑的第一种方法是try catch初始化列表:即

class MyClass{
  private:
    OtherClassThatTrowsOnConstruct member;

    MyClass()
      try:
        member()
      {//Normal constructor
      }
      catch(...)
      {//Can translate an exception but cant stop it.
      }

但是该方法只能用于转换异常,而不是停止它们(如果你不抛出异常,运行时将重新抛出原始异常)。

有些人会说使用动态分配(即带有new和delete关键字的指针),但是当这个库处理进程之间的共享内存时,我有点厌倦了崩溃时动态内存内容会发生什么。其中一个应用程序(例如,析构函数从未被调用,另一个应用程序正在等待不再运行的应用程序,从未意识到它不再在监听)。

1 个答案:

答案 0 :(得分:0)

可以稍微简化第一个版本,而不改变其行为:

MyClass() try {
    memberVariable = class_I_have_no_control_over(24);  // move from temporary
} catch (...) {
    // no need to do anything; memberVariable is already default-constructed

    // Unless the class is so evil that move-assignment might fail and leave
    // the target in a messed-up state. In which case you probably want
    memberVariable = class_I_have_no_control_over();
    // If that fails, you should probably give up and let the exception go.
}

除非你有进一步的限制(例如课程不可移动),否则这是处理你情况的最佳方法。如果它是不可移动的,那么动态分配可能是一个合理的选择;使用智能指针(可能是std::unique_ptr)来确保它与MyClass对象一起被销毁。

#include <memory>

class MyClass{
  private:
    std::unique_ptr<unmovable_evil> memberVariable;

  public:
    MyClass() try {
        memberVariable.reset(new unmovable_evil(24));
    } catch(...) {
        memberVariable.reset(new unmovable_evil);
    }
};

您可能还会将boost::optional视为动态分配的非标准替代方案。