关于iostreams的例外情况

sv9*_*v90 8 c++ iostream exception

我最近了解到,人们可以选择加入iostreams的异常.为了不必手动检查文件是否打开我尝试了,并遇到这种行为:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <sstream>
#include <vector>

void test(std::istream& is, bool exceptions) {
  try {
    if (exceptions)
      is.exceptions(std::istream::failbit);
    std::vector<int> input;
    std::copy(std::istream_iterator<int>{is}, {}, std::back_inserter(input));
    for (auto x : input) {
      std::cout << x << '\n';
    }
  }
  catch (const std::ios_base::failure& f) {
    std::cerr << "Caught error: " << f.what() << '\n';
  }
}

int main() {
  // Emulates file
  std::stringstream ss("1 2 3\n4 5 6\n7 8 9\n");
  test(ss, true);
}
Run Code Online (Sandbox Code Playgroud)

当异常被设置时,这可以正常工作.但是,当我使用异常时,我会抛出一个basic_ios::clear,我想不出原因.

basic_ios::clear未列出可failbit根据cppreference设置的函数.

提前致谢.

编辑:下面的答案已经回答了为什么会这样.我现在的另一个问题是如何避免这种例外?我的第二次尝试是std::copy通过这个循环替换:

for (int n; is >> n;) {
  input.push_back(n);
}
Run Code Online (Sandbox Code Playgroud)

产生了同样的例外.或者这种行为是否有意?

注意: clang不显示此行为.

Ale*_*zzi 3

Jonesinator 已经给了你异常的原因,我想强调的是,错误的存在与异常无关。事实上,您的功能并不等效,您在无异常分支中的操作之后不检查流。事实上,错误正在悄然发生。如果您以等效的方式编写这两个函数,您将得到等效的结果:

#include <iostream>
#include <iterator>
#include <sstream>
#include <vector>

void test_exception(std::istream& is) {
  try {
    is.exceptions(std::istream::failbit);
    std::vector<int> input;
    std::copy(std::istream_iterator<int>{is}, {}, std::back_inserter(input));
    for (auto x : input) {
      std::cout << x << '\n';
    }
  }
  catch (const std::ios_base::failure& f) {
    std::cout << "Caught error: " << f.what() << '\n';
  }
}

void test_error_code(std::istream& is) {    
    std::vector<int> input;
    std::copy(std::istream_iterator<int>{is}, {}, std::back_inserter(input));
    if (!is.good()) {
      std::cout << "Caught error!" << std::endl;
      return;
    }
    for (auto x : input) {
      std::cout << x << '\n';
    }     
}

int main() {
  // Emulates file
  std::stringstream ss_error_code("1 2 3\n4 5 6\n7 8 9\n");
  test_error_code(ss_error_code);

  std::stringstream ss_exception("1 2 3\n4 5 6\n7 8 9\n");
  test_exception(ss_exception);
}
Run Code Online (Sandbox Code Playgroud)

输出:

发现错误!

捕获错误: basic_ios::clear

恕我直言,这是一个很好的例子,为什么在绝大多数情况下异常优于结果代码,并且应该将它们用作默认值。