为什么C++ STL iostream不是"异常友好"?

Rod*_*ddy 45 c++ iostream stl exception

我已经习惯了Delphi VCL框架,其中TStreams会在错误上抛出异常(例如找不到文件,磁盘已满).我正在移植一些代码来代替使用C++ STL,并且已被iostream捕获而不是默认情况下抛出异常,而是设置badbit/failbit标志.

两个问题......

a:为什么这样 - 对于从第一天开始就使用异常构建的语言,这似乎是一个奇怪的设计决策?

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

ken*_*ytm 69

一个.从第一天开始,C++就不会构建异常."C with classes"始于1979年,并且在1989年增加了例外.同时,该streams库早在1984年(后来成为iostreams1989年(后来由GNU于1991年重新实现)编写),它不能在开始时使用异常处理.

参考:

可以使用.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";
  }
  std::cout.flush();

  file.close();

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • @Neil.谢谢 - 但不同意明确关闭()ing - 它就像显式删除autoptr对象! (17认同)
  • @Roddy:是的,他们会在破坏时关闭自己,但他们也会抓住所有可能被`flush()`抛出*的异常.如果它是一个日志文件,那很好.如果它是文档"保存"命令,那么您确实希望确保文件已关闭,如果刷新失败则将其报告给用户.`closing()`一个流就像提交事务一样,或者像复制和交换赋值运算符实现中的`swap()`.这个"提交"步骤在C++中很常见. (16认同)
  • `file.close()` - 你需要吗?我期待他们足够聪明,可以在破坏时关闭... ??? (8认同)
  • @Roddy close()将由stream destuctor调用.但是,明确说出你的意思总是一个好主意. (5认同)
  • 这个例子有点糟糕.如果您启用了eof异常,为什么要测试(错误)eof? (2认同)
  • 最初,流不是模板化的.事实发生后,这一点被加上了. (2认同)

小智 5

正如Kenny所说,如果您愿意,可以启用例外.但是通常I/O在发生错误时需要某种恢复类型的编程,使用异常不容易支持 - 在输入操作更简单之后测试流的状态.我从来没有真正看到任何在I/O上使用异常的C++代码.

  • “某种恢复编程风格” - 我不确定你的意思 - 我经常有类似`while(!completed) {try { doIo();completed=true;} catch (...) { if (promptAbortRetry("whoops!") == ABORT) Completed = true;}` (2认同)
  • @Roddy 通过恢复我的意思是有时需要尝试以一种方式读取值,检测失败,然后尝试以另一种方式读取它。如果使用异常,这就更难了。 (2认同)

Rod*_*ddy 5

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

首先,感谢 KennyTM 的历史。正如他所说,C++从第一天起就没有设计异常,因此后来添加 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";
  }
  std::cout.flush();

  file.close();

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

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