【问题标题】:Catching exceptions from a constructor's initializer list从构造函数的初始化列表中捕获异常
【发布时间】:2010-09-14 16:19:18
【问题描述】:

这是一个奇怪的问题。我有一个 A 类。它有一个 B 类项,我想在 A 的构造函数中使用初始化列表对其进行初始化,如下所示:

class A {
    public:
    A(const B& b): mB(b) { };

    private:
    B mB;
};

有没有办法在仍然使用初始化列表方法的同时捕获 mB 的复制构造函数可能抛出的异常?或者我是否必须在构造函数的大括号中初始化 mB 才能进行 try/catch?

【问题讨论】:

    标签: c++ exception


    【解决方案1】:

    阅读http://weseetips.wordpress.com/tag/exception-from-constructor-initializer-list/)

    编辑:经过更多挖掘,这些被称为“功能尝试块”。

    我承认在我去寻找之前我也不知道这一点。你每天都能学到一些东西!我不知道这是否是对我这些天很少使用 C++、我缺乏 C++ 知识或经常乱扔该语言的拜占庭特性的控诉。嗯,我还是喜欢它:)

    为了确保人们不必跳转到另一个站点,构造函数的函数 try 块的语法原来是:

    C::C()
    try : init1(), ..., initn()
    {
      // Constructor
    }
    catch(...)
    {
      // Handle exception
    }
    

    【讨论】:

    • 呃。有一些方法可以做到这一点,我并不感到惊讶,但这确实是我讨厌 C++ 初始化器语法的一个很好的例子......
    • 注意:在构造函数上使用函数 try 块时,您无法处理异常。即使你的 catch(...) 块没有重新抛出,异常仍然会转义给调用者。
    • 多布斯博士对此有详细解释:drdobbs.com/cpp/184401297
    • Herb Sutter 的“本周大师”文章也对函数尝试块进行了很好的讨论:gotw.ca/gotw/066.htm
    • @Aaron 确实如此,但仍然值得一提的是,您可以重新抛出一个不同的异常,这无论如何都是有用的。假设抛出了一些通用异常,但你宁愿抛出你自己的类型,调用者已经能够处理。
    【解决方案2】:

    不过,您可以使用延迟初始化,即在 MyClass 中为 Reader 保存一个 unique_ptr 并使用 new 创建它。这样,您甚至不需要标志 has_reader,但您可以查看您的 unique_ptr 是否为初始值。

    #include <iostream>
    #include <memory>
    using namespace std;
    
    class MyOtherClass
    {
    public:
        MyOtherClass()
        {
            throw std::runtime_error("not working");
        }
    };
    
    class MyClass
    {
    public:
        typedef std::unique_ptr<MyOtherClass> MyOtherClassPtr;
    
        MyClass()
        {
            try
            {
                other = std::make_unique<MyOtherClass>();
            }
            catch(...)
            {
                cout << "initialization failed." << endl;
            }
    
            cout << "other is initialized: " << (other ? "yes" : "no");
        }
    
    private:
        std::unique_ptr<MyOtherClass> other;
    };
    
    int main()
    {
        MyClass c;
    
        return 0;
    }
    

    当然,也有完全不使用异常的解决方案,但我认为这是您设置的先决条件。

    【讨论】:

      【解决方案3】:

      我知道这个讨论已经有一段时间了。但是 Adam 提到的 try-and-catch 结构是 C++ 标准的一部分,并且受到 Microsoft VC++ 和 GNU C++ 的支持。 这是有效的程序。顺便说一句,catch 会自动生成另一个异常来表示构造函数失败。

      #include <iostream>
      #include <exception>
      #include <string>
      
      using namespace std;
      
      class my_exception: public exception
      {
        string message;
      public:
        my_exception(const char* message1)
        {
          message = message1;
        }
      
        virtual const char* what() const throw()
        {
           cout << message << endl;
           return message.c_str();
        }
      
        virtual ~my_exception() throw() {};
      };
      
      class E
      {
      public:
          E(const char* message) { throw my_exception(message);}
      };
      
      class A
      {
          E p;
      public:
          A()
        try :p("E failure")
          {
                  cout << "A constructor" << endl;
          }
        catch (const exception& ex)
          {
              cout << "Inside A. Constructor failure: " << ex.what() << endl;
          }
      };
      
      
      int main()
      {
          try
          {
              A z;
          }
          catch (const exception& ex)
          {
              cout << "In main. Constructor failure: " << ex.what() << endl;
          }
          return 0;
      }
      

      【讨论】:

        【解决方案4】:

        我不知道你会如何使用初始化列表语法来做到这一点,但我也有点怀疑你是否能够通过在构造函数中捕获异常来做任何有用的事情。显然,这取决于类的设计,但是在什么情况下您将无法创建“mB”,并且仍然有一个有用的“A”对象?

        您不妨让异常向上渗透,并在调用 A 的构造函数的任何地方处理它。

        【讨论】:

        • 也许这应该是一条评论。无论如何,您仍然可以在那里做一些有用的事情,例如诊断问题、记录问题并抛出比您捕获的异常信息更丰富的异常。你是对的,因为你不能对 A 或其成员做任何事情。
        【解决方案5】:

        不是特别漂亮:

        A::A(const B& b) try : mB(b) 
        { 
            // constructor stuff
        }
        catch (/* exception type */) 
        {
            // handle the exception
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-01-19
          • 2010-10-16
          • 2013-07-07
          • 2015-06-11
          • 1970-01-01
          • 1970-01-01
          • 2011-02-09
          相关资源
          最近更新 更多