【问题标题】:How to deal with failed constructor when throwing exceptions is not allowed不允许抛出异常时如何处理失败的构造函数
【发布时间】:2010-07-27 22:30:08
【问题描述】:

我正在查看 Google C++ 样式指南,他们已经决定 not to use exceptions in C++ code,而是依赖返回值。

我的问题是:在这种情况下,您如何处理构造函数中的失败,因为您无法在其中返回值。

谢谢!

【问题讨论】:

  • 不要根据 Google 的代码指南设计现代代码,与良好的 C++ 实践相比,这很糟糕。他们的指南是根据他们现有的代码库量身定制的,这不是好的 C++。
  • 如果您单击 Google 页面上该点旁边的小播放按钮,您会注意到他们将这一点作为支持使用例外的 Pro 提出。另外,请阅读“决定”部分。他们提出了 GMan 的观点——这个决定是为了避免破坏(或不得不重写)整个现有的代码库……所以这不是一个好的榜样。
  • 如果你不使用异常,你就没有正确使用 C++。

标签: c++ constructor exception


【解决方案1】:

我的第一直觉是从构造函数中取出故障点,并创建一个初始化方法。

这样你可以创建你的对象而不用担心失败,然后调用 init() 函数。该函数可以为成功/失败返回类似 int 的内容,例如,如果发生失败,则返回 -1。

是的,这是一个额外的步骤,但它确实可以让你避免构造函数失败

【讨论】:

  • 请参阅www2.research.att.com/~bs/3rd_safe0.html 以获得关于为什么不实现 init() 例程的出色且非常详细的说明。
  • 一般来说(我主要是一个java coder),我不喜欢构造函数中出现异常的可能性,我倾向于采取这种方法。
  • @Dunker:在 C++ 中?不要用 C++ 编写 Java,用 C++ 编写 C++。
  • 完全反对RAII。这就是Java程序员感到困惑的地方。他们一开始就没有 RAII。
  • 这种做法似乎违背了良好的 C++ 实践;但是,考虑到限制,我认为这是最简单的方法。
【解决方案2】:

这很丑陋,但是这样做的方法是保留对象的“特殊状态”来表示“构造失败”。然后你必须查询那个状态。啊!

【讨论】:

    【解决方案3】:

    它们在构造函数中基本上什么都不做。

    也来自 Google C++ 样式指南: 在构造函数中工作 链接▶ 通常,构造函数应该只将成员变量设置为其初始值。任何复杂的初始化都应该在显式的 Init() 方法中进行。

    【讨论】:

    • 可以尝试分配内存,失败。
    • @recip:那将是复杂的初始化。
    【解决方案4】:

    您可以执行以下操作:

    class X;
    class Y;
    
    class Foo
    {
       public:
          //! This function validates the input, and returns an error status if
          //! the Foo can not be created. Otherwise we return a successful status
          //! and output points to a newly constructed Foo. The Foo constructor 
          //! is only called once the inputs are validated.
          //! No exceptions are thrown.
          static Status buildInstance(X const& x, Y const& y, std::auto_ptr<Foo>& output);
    
       private:
          Foo(X const& x, Y const& y);
    };
    

    我过去经常使用这种模式(因为我不得不这样做),但话虽如此,我更喜欢我的构造函数抛出异常。以上内容充其量是不雅的,最坏的情况是相当麻烦。

    【讨论】:

      【解决方案5】:

      我是 C++ 新手,所以我的意见不值得这么多;但我至少遇到过几种不同的方法。

      在我最近使用的一个库中,每个构造函数都有一个int&amp; 参数,它返回构造状态;该库的文档指出,如果构造结果无效,它将调用未定义的行为。这种方法使调用者有责任确保不使用无效类。

      TheClass::TheClass(int &result)
      {
          result = -1; // or some error value
          // do lots of initialisation
          result = 0; // success
      }
      

      我看到的另一个有一个is_valid() 方法。如果构造失败,则将布尔成员变量设置为 false 并从此 is_valid() 方法返回(此方法还检查了其他一些事情)。我设法查看了源代码,发现每个成员函数都以 if(is_valid()) 语句开头。我不能说我是这种方法的粉丝。

      TheClass::TheClass() : m_valid(false)
      {
          // do the initialisation
          if (everything_ok)
              m_valid = true;
      }
      
      void TheClass::method()
      {
          if (!is_valid()) return;
          // do some work
      }
      

      然而,我最近读到异常不再像以前那样缓慢和笨拙,并且可以优雅地实现它们。 Google 可能会出于任何原因禁止它们,但它们仍然是 C++ 语言的一部分。与其用螺丝刀盖房子,不如使用提供的工具。

      【讨论】:

        【解决方案6】:

        您可以设置一个类/对象字段来检查您是否发生错误。

        【讨论】:

        • 如果对象没有被构造,如何检查?
        • @Joe,在构造函数的开头设置标志并在最后清除它。反之亦然。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-10
        • 1970-01-01
        • 2011-11-04
        • 2019-07-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多