Better option than "errno" for file IO error handling I have the following method for opening a file:

void TankFile::OpenForReading(const std::string &amp; 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 &amp; filename)
{
    assert(!filename.empty());

    try
    {
        file.exceptions(std::fstream::failbit);
        file.open(filename, (std::fstream::in | std::fstream::binary));
    }
    catch (std::fstream::failure &amp; 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.
I currently don't see any seamless alternative to using errno and ::strerror;. 

#include &lt;stdexcept&gt;
#include &lt;system_error&gt;
#include &lt;string&gt;
#include &lt;iostream&gt;

#include &lt;cstring&gt; // strerror

#include &lt;fstream&gt;

#if defined(_LIBCPP_VERSION) &amp;&amp; (_LIBCPP_VERSION &gt;= 1000)
#define HAS_IOS_BASE_FAILURE_DERIVED_FROM_SYSTEM_ERROR 1
#else
#define HAS_IOS_BASE_FAILURE_DERIVED_FROM_SYSTEM_ERROR 0
#endif

using std::cerr;
using std::cout;
using std::endl;


int main(/*int argc, char** argv*/) {
    int rv = EXIT_SUCCESS;
    errno = 0;

    try {
        std::ifstream ifs;
        ifs.exceptions(std::ios::badbit | std::ios::failbit);
        ifs.open("DOESN'T EXIST");

    } catch (const std::ios_base::failure&amp; e) {

#if (HAS_IOS_BASE_FAILURE_DERIVED_FROM_SYSTEM_ERROR)
        //
        // e.code() is only available if the lib actually follows iso §27.5.3.1.1
        // and derives ios_base::failure from system_error
        // like e.g. libc++
        // http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/ios?revision=193085&amp;view=markup
        // (line 415)
        //
        // and not keeps on deriving it directly from runtime_error
        // like libstdc++
        // https://github.com/mirrors/gcc/blob/master/libstdc%2B%2B-v3/include/bits/ios_base.h#L209
        //
        cout &lt;&lt; "libc++ error #"    &lt;&lt; e.code().value()  
                &lt;&lt; ' '              &lt;&lt; e.code().message()
                &lt;&lt; ',' &lt;&lt; endl &lt;&lt; "    ";
#endif
        cout &lt;&lt; "libc error #"      &lt;&lt; (rv = errno)
                &lt;&lt; ": "             &lt;&lt; ::strerror(errno)
                &lt;&lt; endl;

        cout &lt;&lt; "handled" &lt;&lt; endl;
    } 

    return rv;
}


using the the new e.code() semantics yields (with clang 3.4 and libc++ 1101) only the first line of

libc++ error #1 unspecified iostream_category error,
    libc error #2: No such file or directory
handled


Live

So even if one's lucky enough to have a std:: implementation that cares about iso §27.5.3.1.1 and actually derives ios_base::failure from system_error, the msg generated is too poor to be presented to users.

The only thing to be discussed is how the libc messages are best incorporated into wrapper classes.