Ok, so I was right, some C++ compilers use quite an expensive method of enabling exceptions:
http://preshing.com/20110807/the-cost-of-enabling-exception-handling
They seem to be installing exception handlers on each entry into a try-catch block or any method that can potentially throw exceptions (which if you enable them globally - is just any method that cannot be statically analyzed it doesn't throw = most of the nontrivial methods calling to other units).
JVM does not need to do it, because it fully controls the environment: it knows the addresses of exception handlers at class-loading time and also knows the stack-frame structure of every loaded method. So, whenever you throw an exception, it can locate all the exception handlers by examining current value of the program counter and it is easy to unwind the stack, because it knows where the return pointers are. So all the cost is offshored to static analysis at classloading / runtime compilation and then to throwing the exception. If you don't throw, there is no cost.
C++ compiler obviously cannot use this technique, because it isn't guaranteed to see all of the code - it can see only a single unit of compilation. Therefore it doesn't know how to unwind the stack of the callers from different units of compilation. Therefore, it can't be precomputed and it has to register/unregister exception handlers dynamically, on method calls, wasting a few CPU cycles per each method.
BTW: additionally Java offers a nice way of throwing very lightweight exceptions that do not collect the stack-trace. They can be used to jump out of deeply recursive calls, something like a non-local but fast goto.
BTW2: Exceptions are also significantly faster than manual checking for nulls everytime, whenever you don't expect nulls to be frequent.
If probablity of null is low, this code is slower on average:
1 2 3 4
|
if (someObject != null)
someObject.doSomething();
else
handleError();
|
than this code:
1 2 3 4 5 6
|
try {
someObject.doSomething();
}
catch (NullPointerException e) {
handleError();
}
|
The latter actually does not use any special instructions for nullchecking, the exception gets triggered by hardware interrupt.