template
struct ForceCheckError {
typedef errorcode codetype;
codetype code;
mutable bool checked;
ForceCheckError()
: checked(true) {}
ForceCheckError(codetype err)
: code(err), checked(false) {}
ForceCheckError(const ForceCheckError& err)
: code(err.code), checked(false) {err.checked = true;}
~ForceCheckError() { assert(checked); }
ForceCheckError& operator=(ForceCheckError& err) {
assert(checked);
code=err.code;
checked=false;
err.checked=true;
return *this;
}
operator codetype&() const {checked=true; return code;}
};
//and in case they get defined recursively (probably via decltype)...
template
struct ForceCheckError >
:public ForceCheckError
{
ForceCheckError()
: checked(true) {}
ForceCheckError(codetype err)
: code(err), checked(false) {}
ForceCheckError(const ForceCheckError& err)
: code(err.code), checked(false) {err.checked = true;}
};
I've never tried it before, but this might be handy, if you prefer error codes, but want to guarantee that they're checked.
ASSERTS should test things that MUST be true, and the program must die immediately if it's false. They should not factor into the exception vs return code debate.
If exceptions are enabled, there is code created in the background to make objects destruct properly during stack unwinding. If you build without exceptions (which is nonstandard), the compiler can emit that code. (In general it's one extra op per function call and one per return, which is nothing) That extra "bloat" will be in every single function that could possibly have to propagate an exception. So, all functions except those with nothrow, throw(), or functions that make no function calls and otherwise throw no exceptions.
On the other hand, nobody checks return values unless forced to, via a helper class like above.