\"We do not use C++ exceptions.\"
If you don\'t use exceptions, what happens when there\'s an error? You just let the program crash?
If you're writing code and reach a point where you've identified an issue for which you would typically throw an exception, but wish to abide by some stipulation that exceptions won't be used, then you have to find another way to let the client code know of the error.
As many existing answers document, you could return a sentinel value (e.g. a true/false success value, an enum). This practice is widely familiar from common C functions specified by POSIX and libc, like fopen(), strstr() or printf().
Another important option is to set some internal state that they can query later. Why might you want or need to do the latter? Because some functions, crucially C++ constructors and operators, don't typically give you the opportunity to return an error code. For example, in:
X x1(something), x2(whatever); fn(x1 + x2);
X::X(...)
can't return anything. X::operator+
may be invoked (assuming +
isn't invoked on results of conversion operators), but fn()
is presumably expecting a const X&
(or X&&
with C++11), and operator+
needs to return an X
so it works in the successful situation. You have no chance to return a distinct type of error code. class X
may need to set some internal state that other code (perhaps fn()
, perhaps a statement after fn()
is called) tests to take appropriate action.
So, you end up with something like:
X x1(something), x2(whatever);
assert(x1.is_valid() and x2.is_valid());
X x3 = x1 + x2;
assert(x3.is_valid());
fn(x3);
Note that this error handling convention is verbose and prone to being overlooked or ignored by client coders - one of the reasons exceptions were created. An interesting variation on this is utilised by most float point hardware - certain operations like division by 0 or under/overflows may set the register to sentinel values such as Not a Number "NaN" or +/- Infinity, and then operations involving an argument in such a state propagate the state to their result. For example, x = 8 + y / 0; z = x + 2;
will set z
to a sentinel too. The idea here is that you can write code that calculates the correct result whenever possible, and check once before using the result to see if an error from anywhere in the calculation code invalidated that result. It works ok for maths code sometimes, particularly when you're not making branching decisions based on the current values of the variables, but unfortunately in many situations you either won't be able or won't want to make all the users of a potentially invalid object code super-defensively to handle and propagate error states.
Using C++ without exceptions serious compromises the usability, maintainability, concision and elegance of the language.
As an alternative to a total ban on exception usage, in some environments you may be able to catch all exceptions at the boundaries of your API, then return error codes or sentinel values in a "C" style. This allows better coding internally, but better interoperability externally. Sadly, sometimes any use of exceptions is impractical, as your code will execute in an environment where the exception-handling mechanisms aren't provided... perhaps inside a kernel, driver, or embedded environment with a stripped down C++-style compiler. Such an environment is not true C++ though, as it's not Standard compliant.