What are the performance implications of using exceptions in C++0x? How much is this compiler dependent? Should we expect to use exceptions more for general logic handling like in Java?
Exception performance is very compiler dependent. You'll have to profile your application to see if it is a problem. In general, it should not be.
You really should use exceptions for "exceptional conditions", not general logic handling. Exceptions are ideal for separating normal paths through your code and error paths.
One would imagine they would have about the same performance as in C++03, which is "very slow!" And no, exceptions should be use in exceptional circumstances due to the try-catch-throw construct, in any language. You're doing something wrong if you are using throw for program flow control in java.
Profiling for exception overhead can be quite tricky, actually... unwinding the call stack may not be observed by the profiler on some platforms.
I don't think C++0x adds to or changes anything in the way C++ exceptions work. For the general advise take a look here.
Exception handling is an expensive feature, in general, because throwing/catching implies additional code to be executed to ensure stack unwinding and catch condition evaluation.
As far as I understood from some readings, for Visual C++, for example, there are some pretty complex structures and logic embedded in the code to ensure that. Since most of the functions might call other functions that might throw exceptions, some overhead for stack unwinding may exist even in these cases.
However, before thinking on exception overhead, it is best to measure the impact of exception usage in your code before any optimization action. Avoiding exception overusage should prevent exception handling significant overheads.
Imagine a bell goes off, the computer stops accepting any input for three seconds, and then someone kicks the user in the head.
That's the cost of an exception. If it's preventing data loss or the machine from catching on fire, it's worth the cost. Otherwise, it probably isn't.
EDIT: And since this got a downvote (plus an upvote, so +8 for me!), I'll clarify the above with less humor and more information: exception, at least in C++ land, require RTTI and compiler and possibly operating system magic, which makes the performance of them a giant black hole of uncertainty. (You aren't even guaranteed that they will fire, but those cases happen during other more serious events, like running out of memory or the user just killing the process or the machine actually catching on fire.) So if you use them, it should be because you want to gracefully recover from a situation that otherwise would cause something horrible to happen, but that recovery cannot have any expectations of running performantly (whatever that may be for your specific application).
So if you are going to use exceptions, you cannot assume anything about the performance implications.
#include <iostream>
#include <stdexcept>
struct SpaceWaster {
SpaceWaster(int l, SpaceWaster *p) : level(l), prev(p) {}
// we want the destructor to do something
~SpaceWaster() { prev = 0; }
bool checkLevel() { return level == 0; }
int level;
SpaceWaster *prev;
};
void thrower(SpaceWaster *current) {
if (current->checkLevel()) throw std::logic_error("some error message goes here\n");
SpaceWaster next(current->level - 1, current);
// typical exception-using code doesn't need error return values
thrower(&next);
return;
}
int returner(SpaceWaster *current) {
if (current->checkLevel()) return -1;
SpaceWaster next(current->level - 1, current);
// typical exception-free code requires that return values be handled
if (returner(&next) == -1) return -1;
return 0;
}
int main() {
const int repeats = 1001;
int returns = 0;
SpaceWaster first(1000, 0);
for (int i = 0; i < repeats; ++i) {
#ifdef THROW
try {
thrower(&first);
} catch (std::exception &e) {
++returns;
}
#else
returner(&first);
++returns;
#endif
}
#ifdef THROW
std::cout << returns << " exceptions\n";
#else
std::cout << returns << " returns\n";
#endif
}
Mickey Mouse benchmarking results:
$ make throw -B && time ./throw
g++ throw.cpp -o throw
1001 returns
real 0m0.547s
user 0m0.421s
sys 0m0.046s
$ make throw CPPFLAGS=-DTHROW -B && time ./throw
g++ -DTHROW throw.cpp -o throw
1001 exceptions
real 0m2.047s
user 0m1.905s
sys 0m0.030s
So in this case, throwing an exception up 1000 stack levels, rather than returning normally, takes about 1.5ms. That includes entering the try block, which I believe on some systems is free at execution time, on others incurs a cost each time you enter try, and on others only incurs a cost each time you enter the function which contains the try. For a more likely 100 stack levels, I upped the repeats to 10k because everything was 10 times faster. So the exception cost 0.1ms.
For 10 000 stack levels, it was 18.7s vs 4.1s, so about 14ms additional cost for the exception. So for this example we're looking at a pretty consistent overhead of 1.5us per level of stack (where each level is destructing one object).
Obviously C++0x doesn't specify performance for exceptions (or anything else, other than big-O complexity for algorithms and data structures). I don't think it changes exceptions in a way which will seriously impact many implementations, either positively or negatively.
I once created an x86 emulation library and used exceptions for interrupts and such. Bad idea. Even when I was not throwing any exceptions, it was impacting my main loop a lot. Something like this was my main loop
try{
CheckInterrupts();
*(uint32_t*)&op_cache=ReadDword(cCS,eip);
(this->*Opcodes[op_cache[0]])();
//operate on the this class with the opcode functions in this class
eip=(uint16_t)eip+1;
}
//eventually, handle these and do CpuInts...
catch(CpuInt_excp err){
err.code&=0x00FF;
switch(err.code){
The overhead of containing that code in a try block made the exception functions the 2 of the top 5 users of CPU time.
That, to me is expensive
There's no reason why exceptions in C++0x should be either faster or slower than in C++03. And that means their performance is completely implementation-dependant. Windows uses completely different data structures to implement exception handling on 32-bit vs 64-bit, and on Itanium vs x86. Linux isn't guaranteed to stick with one and just one implementation either. It depends. There are several popular ways to implement exception handling, and all of them have advantages and downsides.
So it doesn't depend on language (c++03 vs 0x), but on compiler, runtime library, OS and CPU architecture.
I basically think the wrong question has been asked.
What is the cost of exception is not usefull, more usefull is the cost of exceptions relative to the alternative. So you need to measure how much exceptions cost and compare that to returning error codes >>>AND<<< checking the error codes at each level of the stack unwind.
Also note using exceptions should not be done when you have control of everything. Within a class returning an error code is probably a better technique. Exceptions should be used to transfer control at runtime when you can not determine how (or in what context) your object will be utilised at runtime.
Basically it should be used to transfer control to higher level of context where an object with enough context will understand how to handlle the exceptional situation.
Given this usage princimple we see that exceptions will be used to transfer control up multiple levels in stack frame. Now consider the extra code you need to write to pass an error code back up the same call stack. Consider the extra complexity then added when error codes can come from multiple different directions and try and cordinate all the different types of error code.
Given this you can see how Exceptions can greatlly simplify the flow of the code, and you can see the enhirit complexity of the code flow. The question then becomes weather exceptions are more expensive than the complex error conditions tests that need to be performed at each stack frame.
The answer as always depends (do both profile and use the quickist if that is what you need).
But if speed is not the only cost.
Maintainability is a cost that can be measured. Using this metric of cost Exceptions alway win as they ultimately make the constrol flow of the code to just the task that needs to be done not the task and error control.