【问题标题】:C++ - Where to throw exception?C++ - 在哪里抛出异常?
【发布时间】:2010-06-07 15:39:18
【问题描述】:

我有一个意识形态问题,所以:

假设我有一些模板函数

template <typename Stream>
void Foo(Stream& stream, Object& object) { ... }

用这个objectstream 做一些事情(例如,序列化该对象到流或类似的东西)。

假设我还添加了一些普通的包装器,例如 (假设这些包装器的数量等于 2 或 3):

void FooToFile(const std::string& filename, Object& object)
{
   std::ifstream stream(filename.c_str());
   Foo(stream, object);
}

所以,我的问题是:

如果我的stream 不好,在这种情况下(从意识形态上)我应该在哪里抛出异常?我应该在每个包装器中执行此操作还是将检查移至我的Foo,以便它的主体看起来像

if (!foo.good()) throw (something);
// Perform ordinary actions

我知道这可能不是编码中最重要的部分,而且这些解决方案实际上是平等的,但我只是想知道“正确的” 方法来实现它。

谢谢。

【问题讨论】:

    标签: c++ exception stream


    【解决方案1】:

    在这种情况下,最好将其抛出到较低级别的 Foo 函数中,这样您就不必在所有包装器中复制验证和异常抛出代码。通常,正确使用异常可以通过删除大量数据验证检查来使您的代码更加简洁,否则您可能会在调用堆栈的多个级别上进行冗余检查。

    【讨论】:

    • +1 : 避免剪切和粘贴是编程的最终目标:)
    【解决方案2】:

    我不希望延迟通知错误。如果您在创建流之后知道它不好,为什么要调用对其有效的方法?我知道为了减少代码冗余,您计划将其进一步降低。但是这种方法的缺点是一个不太具体的错误消息。所以这在某种程度上取决于源代码上下文。如果您可以在较低功能级别避免通用错误消息,您可以在那里添加代码,这肯定会简化代码的维护,特别是当团队中有新开发人员时。如果您需要特定的错误消息,最好在故障点自行处理。

    为避免代码冗余,请调用一个为您生成此异常/错误的通用函数。不要在每个包装器中复制/粘贴代码。

    【讨论】:

      【解决方案3】:

      越早发现异常越好。异常越具体 - 越好。除了声明之外,不要害怕将大部分代码包含在 try catch 块中。

      例如:

      int count = 0;
      bool isTrue = false;
      MyCustomerObject someObject = null;
      
      try
      {
         // Initialise count, isTrue, someObject. Process.
      }
      catch(SpecificException e)
      {
      // Handle and throw up the stack. You don't want to lose the exception.
      }
      

      【讨论】:

        【解决方案4】:

        我喜欢为此使用辅助函数:

        struct StreamException : std::runtime_error
        { 
            StreamException(const std::string& s) : std::runtime_error(s) { }
            virtual ~StreamException() throw() { }
        };
        
        void EnsureStreamIsGood(const std::ios& s)
        {
            if (!s.good()) { throw StreamException(); }
        }
        
        void EnsureStreamNotFail(const std::ios& s)
        {
            if (s.fail()) { throw StreamException(); }
        }
        

        如果我预计不会失败,我会在执行流操作之前和之后立即测试它们。

        【讨论】:

          【解决方案5】:

          传统上,在 C++ 中,流操作不会引发异常。这部分是出于历史原因,部分是因为流式传输失败是预期的错误。 C++ 标准流类处理此问题的方式是在流上设置一个标志以指示发生了错误,用户代码可以检查该标志。与抛出异常相比,不使用异常使恢复(流操作通常需要)更容易。

          【讨论】:

          • 仍然存在流对象的异常掩码,以防万一发生坏事时想要异常。在我看来,它应该设置为 badbit: 提取失败,正如你所说,是预期的,以及 eof,但如果出现 IO 错误,你无能为力,至少不能在你的“普通”文件中读/写代码。
          猜你喜欢
          • 2016-03-10
          • 2013-02-08
          • 2019-01-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-15
          • 1970-01-01
          • 2013-03-23
          相关资源
          最近更新 更多