class File_handle {
FILE *p;
public:
File_handle(const char *pp, const char *r) { p = fopen(pp, r); }
~File_handle() { if ( p ) fclose(p); }
FILE* file() const { return p; }
};
void f(string s)
{
File_handle fh { s, "r"};
if ( fh.file() == NULL ) {
fprintf(stderr, "failed to open file '%s', error=%d\n", p, errno);
return;
}
// use fh
}However, where the language and it's objects and memory ends and the external world begins, like files and sockets... that's always tricky.
Do you mind to elaborate what you believe are the misunderstandings? Examples of incorrect/inaccurate statements and/or an article with better explanations of mentioned use cases would be helpful.
> it's called std::expected
How does std::expected play together with all other possible error handling schemas? Can I get unique ids for errors to record (error) traces along functions? What is the ABI of std::expected? Stable(ish) or is something planned, ideally to get something C compatible?
Regardless, in his example, he could achieve what he wants by wrapping the try in a lambda, and returning either the value from try or nullopt from catch. But clearly, that's just converting exceptions to another error-handling mechanism because he isn't doing it right.
He claimed that not handling an exception causes the program to crash, that's just plain incorrect. To be fair many people use the term "crash" liberally.
std::expected or equivalent is often used with std::error_code, which is an extensible system (error codes are arranged in categories) that among others interops with errno.
Tell that to Bjarne!
Exceptional C++, by Herb Sutter is an excellent resource that explains this. It’s quite outdated these days but the core concepts still hold well.
When done well, most of your code can be happy path programming with errors/invalid state taken care of mostly automatically.
However it’s also very easy not to do this well, and that ends up looking like the suggestions the author of the article makes.
Occasionally I do like to use auto or lambdas from C++11 but even then I have to remember more rules for initialization because braces were introduced.
But now the language packs so much complexity that I can't be sure I understand all of the code I'm looking at.
My usual quality standard for production code is that it doesn't just need to be correct, it needs to be obviously correct. So that's a problem.
Doubly so when the other programmers on the team aren't C++ geeks.
struct File_handle {
static auto Create(std::string const & pp, const char *r) -> std::expected<File_handle, std::error_code> {
auto p = fopen(pp.c_str(), r);
if (!p) return std::unexpected(error_code_from_errno(errno));
return File_handle{p};
}
~File_handle() { fclose(p); }
private:
File_handle(FILE * f) : p{f} {}
FILE *p;
};
Also Bjarne's control of C++ is quite limited, and he is semi-retired, so asking him to "fix his language" is fairly misguided. It's designed by a committee of 200+ people.
Anyway what you want seems to be to not use exceptions, but monads instead. These are also part of the standard, it's called std::expected.