I'm using fstream. Is there any way to get the failure message/exception?
For example if I'm unable to open the file?
Streams by default do not throw exceptions on error, they set flags. You can make them throw exceptions by using the stream's exception() member function:
ifstream ifs;
ifs.exceptions( std::ios::failbit ); // throw if failbit get set
Theoretically, you could then do something like this:
try {
int x;
ifs >> x;
}
catch( const std::exception & ex ) {
std::cerr << "Could not convert to int - reason is "
<< ex.what();
}
Unfortunately, the C++ Standard does not specify that thrown exceptions contain any error message, so you are in implementation specific territory here.
Short answer: no. Even checking errno
after you detect failure (using e.g. bad()
, fail()
) after various operations doesn't reliably work. Creating an ifstream
/ofstream
wrapping a file that can't be opened doesn't necessarily set a failure bit until you try to read, write, or close it.
Long answer: you can call ios::exceptions(ios_base::iostate)
to request that ios_base::ios_failure
exceptions be thrown when a corresponding bit (badbit, failbit, eofbit) is set, but this (at least on GNU and Microsoft C++ libraries) doesn't get you any more information than manually checking the bits, and ends up being largely pointless, IMHO.
From checking it out I found that also errno
and also GetLastError()
do set the last error and checking them is quite helpful. For getting the string message use:
strerror(errno);
If you are looking for a more detailed message than what is provided by std::ios_base::failure
then here is an example which uses errno
to re-raise a std::system_error
:
terminate called after throwing an instance of 'std::system_error'
what(): broken/path: No such file or directory
#include <fstream>
int main() {
const std::string filename{ "broken/path" };
try {
std::ifstream file{ filename };
file.exceptions(std::ios::failbit); // std::ios_base_failure is thrown here
} catch (std::ios_base::failure&) {
throw std::system_error{ errno, std::generic_category(), filename };
}
}
This works on UNIX and Windows because "All errno
values are … UNIX-compatible" (source).
If you want even-more-specific Windows error codes (i.e. file is already open in another program), you should look to the platform-specific GetLastError()
api instead of errno
.