为什么 C++ STL iostream 不“异常友好”?

问题描述 投票:0回答:4

我习惯了 Delphi VCL 框架,其中 TStream 会在错误时抛出异常(例如,文件未找到、磁盘已满)。我正在移植一些代码以使用 C++ STL,并且被 iostreams 发现,默认情况下不抛出异常,而是设置 badbit/failbit flags

两个问题...

a:为什么会这样 - 对于一种从第一天起就存在异常的语言来说,这似乎是一个奇怪的设计决策?

b:如何最好地避免这种情况?我可以生成按照我的预期抛出的垫片类,但这感觉就像重新发明轮子。也许有一个 BOOST 库可以以更理智的方式做到这一点?

c++ exception stl iostream
4个回答
77
投票
  1. C++ 从第一天起就没有例外。 “带类的 C”始于 1979 年,并于 1989 年添加了例外。同时,

    streams
    库早在 1984 年就已编写(后来在 1989 年成为
    iostreams
    (后来由 GNU 于 1991 年重新实现)),它只是不能一开始就使用异常处理。

    参考:

  2. 可以使用

    .exceptions
    方法启用例外。

// ios::exceptions
#include <iostream>
#include <fstream>
#include <string>

int main () {
    std::ifstream file;
    file.exceptions(ifstream::failbit | ifstream::badbit);
    try {
        file.open ("test.txt");
        std::string buf;
        while (std::getline(file, buf))
            std::cout << "Read> " << buf << "\n";
    }
    catch (ifstream::failure& e) {
        std::cout << "Exception opening/reading file\n";
    }
}

5
投票

好的,现在是“回答我自己的问题”时间...

首先,感谢 KennyTM 的历史。正如他所说,C++ 从第一天起就设计为NOT,因此 iostreams“异常”处理后来被附加也就不足为奇了。

其次,正如 Neil B 指出的那样,输入格式转换错误出现异常将是一个巨大的痛苦。这让我感到惊讶,因为我将 iostreams 视为一个简单的文件系统包装层,而我根本没有考虑过这种情况。

第三,看来 BOOST 确实给聚会带来了一些东西:Boost.IOStreams。如果我理解正确的话,它们处理流的低级 I/O 和缓冲方面,而让常规的 c++ IOStreams 库来处理转换问题。 Boost.IOStreams 确实以我期望的方式使用异常。如果我理解正确的话,肯尼的例子也可能是这样的:

#include <ostream>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/stream.hpp>

int main () {
  boost::iostreams::stream_buffer <boost::iostreams::file_source> buf("test.txt");
  std::istream file(&buf);

  try {
    std::string buf;
    while (std::getline(file, buf))
      std::cout << "Read> " << buf << "\n";
  }
  catch (std::ios_base::failure::failure e) {
    std::cout << "Exception opening/reading file\n";
  }

  return 0;
}

认为在这个版本中,应该会抛出“文件未找到”之类的错误,但“istream”错误将由 badbit/failbit 报告。


3
投票

正如肯尼所说,如果您愿意,您可以启用例外。但通常 I/O 在发生错误时需要某种恢复风格的编程,而使用异常不容易支持这一点 - 在输入操作后测试流的状态要简单得多。我从未真正见过任何在 I/O 上使用异常的 C++ 代码。


2
投票
  1. 每当抛出异常时,您都需要考虑异常安全。所以没有例外,没有例外,没有例外——安全头痛。

  2. Iostream 还支持异常。但抛出异常是可选的。您可以通过设置

    exceptions (failbit | badbit | eofbit)

  3. 来启用例外
  4. Iostreams 让您可以接受异常和无期望的行为。

© www.soinside.com 2019 - 2024. All rights reserved.