I have the following method for opening a file:
void TankFile::OpenForReading(const std::string & filename)
{
assert(!filename.empty());
errno = 0;
file.exceptions(0); // Don't throw
file.open(filename, (std::fstream::in | std::fstream::binary));
if (!file.is_open() || !file.good())
{
const char * errorStr = strerror(errno);
throw TankFileError(Format("Failed to open Tank file \"%s\": '%s'", filename.c_str(), errorStr));
}
}
The objective here is to attempt to open a file and throw TankFileError
with a proper error description on failure. The caller will be expecting this exception type.
Everything works fine and I get a nice error message like this if the exception is thrown:
Failed to open Tank file "unexistent_file": 'No such file or directory'
But what I don't like in that block is having to use the errno
global and strerror()
.
A way around it would be to let the stream throw an exception, then catch it, get the error message from the what()
member and re-throw with TankFileError
, but I find this solution also a bit hackish, plus, in the tests I did, the resulting error message from std::fstream::failure
was pretty cryptic:
void TankFile::OpenForReading(const std::string & filename)
{
assert(!filename.empty());
try
{
file.exceptions(std::fstream::failbit);
file.open(filename, (std::fstream::in | std::fstream::binary));
}
catch (std::fstream::failure & err)
{
throw TankFileError(Format("Failed to open Tank file \"%s\": '%s'", filename.c_str(), err.what()));
}
}
Produced the error message:
Failed to open Tank file "unexistent_file": 'ios_base::clear: unspecified iostream_category error'.
Is there a better way to implement this? I was hoping that the new C++11 system_error
library would provide a way to query this kind of error messages, but from what I've seen, you still have to pass errno
around to get an error string.
std::ios::failure
are pretty useless. \$\endgroup\$