For more than 25 years continues a discussion in C++ community about exceptions. In our opinion this can only be compared with math community and their open problems like Hilbert's 23 problems dated by 1900.
In essence C++ exception discussion is about efficiency of exceptions vs status codes. This problem is not so acute in other languages (like java or C#) because those languages postulate different goals.
C++ designers have introduced a zero-overhead principle for any language feature, which is:
Exceptions comparing to status codes do not withstand this demand. This led to the fragmentation of C++ comunity where many big projects and code styles ban exceptions partially or completely.
Make no doubt that all this time people were trying to make exceptions better, and have found techniques to make them space and run time efficient to some extent, but still, old plain status codes outperform both in speed (especially in predictability of time of exception handling logic) and in code size.
We guess the solution is finally found after the quarter the century of discussion!
WG paper: Zero-overhead deterministic exceptions: Throwing values by Herb Sutter. This "paper aims to extend C++’s exception model to let functions declare that they throw a statically specified type by value. This lets the exception handling implementation be exactly as efficient and deterministic as a local return by value, with zero dynamic or non-local overheads."
In other words author suggests to:
Here are author's arguments:
if
switch
What aurhor suggests might seem too radical but at present it's only viable solution to reestablish zero-verhead principle and to reunite two C++ camps.
Here is the approach.
Are contract violation like invalid values of arguments or invalid post conditions (unhold invariants) are exceptions or programmer's bugs?
If later then it's best to terminate, as you cannot correctly recover from bug.
What user program can do with stack overflow?
The best according to the author it to terminate.
What is the best way to deal with OOM dyring dynamic allocation.
At present there are two operators:
new
bad_alloc
new(nothrow)
nullptr
Herb Sutter suggests to change new behavior to terminate on failure (it is very hard to properly handle bad_alloc anyway), while new(nothrow) will still allow to build code that can deal with OOM.
This should never be reported as an error, and status codes should be used to report the state.
This is where exceptions should be used.
Statistics shows that with such separation more than 90% of what curently is an exception will not be exception any more, so no any hidden exception logic is required: program either works or terminates.
Redefine what exception object is and how it is propagated.
It should be thin value type. At minimum it needs to contain an error code. Suggested size is up to a couple of pointers.
Compiler should be able to cheaply allocate and copy it on the stack or even in the processor's registers.
Such simple exception type resolves problems with lifetime of exception object, and makes exception handling as light as checking status codes.
Exception should be propagated through return chanel, so it's like a new calling convention that defines either function result or error outcome.
It's not our intention to quote whole the paper here. If you're interested then please read it. Here we want to outline our concerns.
This paper emphasizes that exception type should be small.
So, what to do with exception payload, if any (at least error message if it's not a static text)?
If this won't be resolved then developers will start to invent custom mechanisms like GetLastErrorMessage().
And what to do with aggregate exceptions?
We think this must be clearly addressed.
We can accept that most of the current exceptions will terminate.
But consider now some container that serves requests, like web container or database.
It may be built from multiple components and serve multiple requests concurently. If one request will terminate we don't want for container to terminate.
If terminate handler is called then we cannot rely on state of the application. At least we can expect heap leaks and un-released resources.
So, we either want to be able release heap and other resources per request, or we want to go down with whole process and let OS deal with it.
In the later case we need to design such containers differently: as a set of cooperative processes; OS should allow to spin processes more easily.
There are Virtual Machines that allow exception to be thrown on each instruction (like JVM, or CLI).
You cannot tell in this case that code would never throw exception, as it can out of the blue!
Event in x86 you can have PAGE FAULT on memory access, which can be translated into an exception.
So, it's still a question whether the terminate() solution is sound in every case, and whether compiler can optimize out exception handling if it proves staticlly that no exception should be thrown.