I just encountered a case where an exception of type std::ios_base::failure
was thrown inside a try
block that catches this type of exception, but it does not get caught.
Minimal working example
#include <fstream>
#include <iostream>
int main()
{
std::ofstream file;
file.exceptions( std::ofstream::failbit );
try {
file.open( "no_write_access" );
} catch ( const std::ios_base::failure& e ) {
std::cout << "Look, Ma, I caught an error!" << std::endl;
}
}
Compilation and execution
% g++ --version
g++ (GCC) 6.1.0
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% g++ main.cpp -std=c++11 -o test && ./test
terminate called after throwing an instance of 'std::ios_base::failure'
what(): basic_ios::clear
[1] 9734 abort ./test
Discussion
What's going on here? The "terminate" message explicitly specifies that the type of the exception was std::ios_base::failure
, so I can't see any reason it would not get caught.
An interesting clue is that the catch
block does work if I catch a const std::exception&
, but it does not work if I catch a const std::runtime_error&
(which, in C++11, is a base class of std::ios_base::failure
, according to cppreference).
EDIT: I just tried g++
9.2.0 and it works correctly. I tried a few different versions and the behavior changes sometime between 6.3.0 and 7.2.0. I'm still curious if anyone knows the reason, but it looks like it may have something to do with a bug in gcc
itself.