Are exceptions in C++ really slow?
Asked Answered
O

6

129

I was watching Systematic Error Handling in C++—Andrei Alexandrescu he claims that Exceptions in C++ are very very slow.

Is this still true for C++98?

Oversoul answered 12/12, 2012 at 8:41 Comment(8)
It makes no sense to ask if "C++98 exceptions" are faster/slower than "C++03 exceptions" or "C++11 exceptions". Their performance is dependent on how the compiler implements them in your programs, and the C++ standard says nothing about how they should be implemented; the only requirement is that their behavior must follow the standard (the "as-if" rule).Peper
Related (but not really duplicate) question: #691668Slack
yes, it is very slow, but they should not be thrown for a normal operations or used as a branchPaiz
I've found a similar question.Lip
To clarify what BЈовић has said, using exceptions is not something to be scared of. It is when an exception is thrown that you encounter (potentially) time consuming operations. I am also curious as to why you want to know for C++89 specifically... that latest version is C++11, and the time that it takes for exceptions to run is implementation defined, hence my 'potentially' time consuming.Lit
it makes no sense to ask whether the c++98 standard impacted on exception performance. likewise, it makes no sense to ask that about the c++03 standard (which was just a technical corrigendum). you might meaningfully ask that about c++11, however, where the exception handling mechanism was extended with new features.Costumier
@Insilico: the C++11 standard makes some rather strong suggestions about how the current exception should be stored, and constrains the possible solutions.Costumier
In the situation Alexandrescu describes, exceptions were being used for IO errors. I think the lesson is that if a code path is expected to be common or speed on that path is a significant concern, then that code path shouldn't go through an exception throw. Once significant errors have occurred in a program, speed becomes less of a concern and the tradeoffs exceptions offer can make a lot of sense.Graniah
S
210

The main model used today for exceptions (Itanium ABI, VC++ 64 bits) is the Zero-Cost model exceptions.

The idea is that instead of losing time by setting up a guard and explicitly checking for the presence of exceptions everywhere, the compiler generates a side table that maps any point that may throw an exception (Program Counter) to the a list of handlers. When an exception is thrown, this list is consulted to pick the right handler (if any) and stack is unwound.

Compared to the typical if (error) strategy:

  • the Zero-Cost model, as the name implies, is free when no exceptions occur
  • it costs around 10x/20x an if when an exception does occur

The cost, however, is not trivial to measure:

  • The side-table is generally cold, and thus fetching it from memory takes a long time
  • Determining the right handler involves RTTI: many RTTI descriptors to fetch, scattered around memory, and complex operations to run (basically a dynamic_cast test for each handler)

So, mostly cache misses, and thus not trivial compared to pure CPU code.

Note: for more details, read the TR18015 report, chapter 5.4 Exception Handling (pdf)

So, yes, exceptions are slow on the exceptional path, but they are otherwise quicker than explicit checks (if strategy) in general.

Note: Andrei Alexandrescu seems to question this "quicker". I personally have seen things swing both ways, some programs being faster with exceptions and others being faster with branches, so there indeed seems to be a loss of optimizability in certain conditions.


Does it matter ?

I would claim it does not. A program should be written with readability in mind, not performance (at least, not as a first criterion). Exceptions are to be used when one expects that the caller cannot or will not wish to handle the failure on the spot, and would rather pass it down the call stack. Bonus: in C++11 exceptions can be marshalled between threads using the Standard Library.

This is subtle though, I claim that map::find should not throw but I am fine with map::find returning a checked_ptr which throws if an attempt to dereference it fails because it's null: in the latter case, as in the case of the class that Alexandrescu introduced, the caller chooses between explicit check and relying on exceptions. Empowering the caller without giving him more responsibility is usually a sign of good design.

Sorcerer answered 12/12, 2012 at 9:11 Comment(20)
+1 I would only add four things: (0) about the support for rethrowing added in C++11; (1) a reference to committee's report on c++ efficiency; (2) some remarks about correctness (as trumping even readability); and (3) about the performance, remarks about measuring it against the case of not using exceptions (all is relative)Costumier
this is false("So, yes, exceptions are slow on the exceptional path, but they are otherwise quicker."). Aleandrescu said that exceptions cause noticeable slowdown because they limit what optimizer can do. Check Going Native Panel.Lamp
@NoSenseEtAl: Maybe, maybe not. He said it, but it did not present any figure nor did he explain why the presence of exceptions would trump optimizers. More specifically he did not precise whether this was intrinsic (which I doubt) or just a limitation of the optimizer(s) he used.Sorcerer
@Cheersandhth.-Alf: (0), (1) and (3) done: thanks. Regarding correctness (2), while it trumps readability I am unsure about exceptions leading to more correct code than other error-handling strategies (it's so easy to forget about the many invisible paths of execution exceptions create).Sorcerer
The description may be locally correct, but it may be worth noting that the presence of exceptions has global implications on assumptions and optimizations the compiler can make. These implications suffer the problem that they have "no trivial counter-examples", since the compiler can always see through a small program. Profiling on a realistic, large code base with and without exceptions may be a good idea.Heavily
> the Zero-Cost model, as the name implies, is free when no exception occurs this is not actually true down to the finest levels of detail. generating more code always has a performance impact, even if small and subtle... it might take a tiny bit longer for the OS to load the executable, or you will get more i-cache misses. also, what about stack unwinding code? also, what about the experiments that you can do to measure the effects instead of trying to understand it with rational thought?Trudy
@jheriko: I believe I addressed most of your questions already, actually. The time to load should not be impacted (cold code should not be loaded), the i-cache should not be impacted (cold code should not make it into the i-cache), ... so to address the one missing question: "how to measure" => replacing any exception thrown with a call to abort will allow you to measure the binary-size footprint and check that the load-time/i-cache behave similarly. Of course, better not hit any of the abort...Sorcerer
it might be pedantic, but doing anything like this costs 'something'. its not like the implementation is carefully positioning itself to work in some otherwise available idle-time etc. so its not 'free'. i'm pretty sure its unreasonable to expect an implementation that does as well as doing nothing though. it certainly makes the performance cost of using exceptions a lot more palatable vs. the disadvantage of not using them. my main gripe is that without throwing anything, if i turn on exceptions using clang, gcc or cl compilers i can measure the performance difference and it is signifcant.Trudy
(p.s. i could look into it, but its easier to leave them off, i don't use them anyway because of legacy /extreme/ performance impacts - but this is what stops me turning them on and changing my programming style - probably because i work in an environment where framerate is king, and crashes are already extremely rare - but maybe some of the problem is that i don't turn on RTTI for similar reasons, it slows everything down by a measurable amount.)Trudy
@jheriko: two points (1) exceptions are free on the non-exceptional path if the ABI uses the Zero-Cost exception model, a notable exception being Win32 and (2) free on the non-exceptional path does not mean free in general, as detailed in the answer there is a substantial penalty in terms of used disk space (which might impact library loading time if the loader is dumb) and as you mention many runtime tie the use of exceptions to the use of RTTI and enabling RTTI may have a cost of its own (additional binary bloat, ...). For a typical user (RTTI enabled, modern platform), they are not slow.Sorcerer
@NoSenseEtAl, I believe, Aleandrescu's claim of 7% performance penalty of exceptions, is to compare C++ f(); g(); h(); ... where f, g, h might throw so reordering can't happen, vs. C f(); g(); h();... where they don't throw. What @MatthieuM. is talking about is it is quicker to write in C++ f(); g(); h(); ... than in C++ if (f() == -1) return -1; if (g() == -1) return -1; if (h() == -1) return -1;. The point is, if you are using C++ and enables exception (STL won't work if you don't nowadays), 7% penalty is inevitable. It is quicker to use exception than return code in this caseSena
Wouldn't it be a really good solution to save an offset to the appropriate catch block with each try block on compile so when the try is entered at runtime the pointer is pushed onto a stack (let's call it 'topmost-exception-handler-pointer-stack'; terrible name, I know). Then when an exception is thrown, a pointer is popped from that stack and execution jumps to that block (if any). If rethrown the next handler pointer is popped from the stack, etc. Isn't this a "near perfect solution"™ or am I missing something major?Kamalakamaria
@itzJanuary: Just because there is a try block doesn't mean that its catch is appropriate for the exception that is going to be thrown; and since multiple exceptions can be thrown (think std::bad_alloc, std::out_of_range and your custom ClientNotFound), the "matching" catch block may differ on a per-exception basis. Add in the fact that you may put a try around a call to a closed-source 3rd-party library, or a dynamically-linked library, and there is no way you can know at compile-time which exception is going to get thrown.Sorcerer
@MatthieuM. I'm not really talking about pure C++ but rather a technique that would require intrinsic support by it. Each throw does the stack lookup, multiple catches can just be put on the stack as though they were nested, the first of the multiple catches is put on the stack last (this would also implicitly do the catch matching we want). On exception throw just walk the stack backwards and find the first catch appropriate for that exception.Kamalakamaria
So looks like Exceptions beat "if else {}" in an intensely iterative setup, if probability of exception or an "if(errorcheck)" turning positive is rather less, then "if else{}" beats all the extra Exeception mechanism?Nikolai
@Ace: I've amended the answer, as recent benchmarks I've made have been inconclusive. In the absence of errors, I've now seen both exceptions and branches being faster than the other on different benchmarks. Branches are indeed always faster in the presence of errors.Sorcerer
@MatthieuM. Suppose a hypothetical language provides concise and cleaner syntax to write error-code base handling style, then which one would you prefer? error-code or exceptions?Playful
@SouravKannanthaB: No need for hypothetical. At the moment, I would argue that Rust hits the sweet spot: Option/Result are clean way to signal the absence of value, or that an error occurred, and the ? operator to "bubble up" errors makes it very clean (and yet explicit) at the call site. Throw in panics for the "should be impossible" cases -- so as to avoid cluttering all result types -- and ergonomics are really good.Sorcerer
Cool... Just glanced it.. What are the criticism it is facing?Playful
The discussion gets much more complicated than a comment allows; really. And of course I likely have some bias of my own. I'll invite you to do your own research :)Sorcerer
C
72

When the question was posted I was on my way to the doctor, with a taxi waiting, so I only had time then for a short comment. But having now commented and upvoted and downvoted I’d better add my own answer. Even if Matthieu’s answer already is pretty good.


Are exceptions especially slow in C++, compared to other languages?

Re the claim

“I was watching Systematic Error Handling in C++—Andrei Alexandrescu he claims that Exceptions in C++ are very very slow.”

If that’s literally what Andrei claims, then for once he’s very misleading, if not downright wrong. For a raised/thrown exceptions is always slow compared to other basic operations in the language, regardless of the programming language. Not just in C++ or more so in C++ than in other languages, as the purported claim indicates.

In general, mostly regardless of language, the two basic language features that are orders of magnitude slower than the rest, because they translate to calls of routines that handle complex data structures, are

  • exception throwing, and

  • dynamic memory allocation.

Happily in C++ one can often avoid both in time-critical code.

Unfortunately There Ain’t No Such Thing As A Free Lunch, even if the default efficiency of C++ comes pretty close. :-) For the efficiency gained by avoiding exception throwing and dynamic memory allocation is generally achieved by coding at a lower level of abstraction, using C++ as just a “better C”. And lower abstraction means greater “complexity”.

Greater complexity means more time spent on maintenance and little or no benefit from code reuse, which are real monetary costs, even if difficult to estimate or measure. I.e., with C++ one can, if so desired, trade some programmer efficiency for execution efficiency. Whether to do so is largely an engineering and gut-feeling decision, because in practice only the gain, not the cost, can be easily estimated and measured.


Are there any objective measures of C++ exception throwing performance?

Yes, the international C++ standardization committee has published a Technical Report on C++ performance, TR18015.


What does it mean that exceptions are “slow”?

Mainly it means that a throw can take a Very Long Time™ compared to e.g. an int assignment, due to the search for handler.

As TR18015 discusses in its section 5.4 “Exceptions” there are two principal exception handling implementation strategies,

  • the approach where each try-block dynamically sets up exception catching, so that a search up the dynamic chain of handlers is performed when an exception is thrown, and

  • the approach where the compiler generates static look-up tables that are used to determine the handler for a thrown exception.

The first very flexible and general approach is almost forced in 32-bit Windows, while in 64-bit land and in *nix-land the second far more efficient approach is commonly used.

Also as that report discusses, for each approach there are three main areas where exception handling impacts on efficiency:

  • try-blocks,

  • regular functions (optimization opportunities), and

  • throw-expressions.

Mainly, with the dynamic handler approach (32-bit Windows) exception handling has an impact on try blocks, mostly regardless of language (because this is forced by Windows' Structured Exception Handling scheme), while the static table approach has roughly zero cost for try-blocks. Discussing this would take a lot more space and research than is practical for an SO answer. So, see the report for details.

Unfortunately the report, from 2006, is already a little bit dated as of late 2012, and as far as I know there’s not anything comparable that’s newer.

Another important perspective is that the impact of use of exceptions on performance is very different from the isolated efficiency of the supporting language features, because, as the report notes,

“When considering exception handling, it must be contrasted to alternative ways of dealing with errors.”

For example:

  • Maintenance costs due to different programming styles (correctness)

  • Redundant call site if failure checking versus centralized try

  • Caching issues (e.g. shorter code may fit in cache)

The report has a different list of aspects to consider, but anyway the only practical way to obtain hard facts about the execution efficiency is probably to implement the same program using exception and not using exceptions, within a decided cap on development time, and with developers familiar with each way, and then MEASURE.


What is a good way to avoid the overhead of exceptions?

Correctness almost always trumps efficiency.

Without exceptions, the following can easily happen:

  1. Some code P is meant to obtain a resource or compute some information.

  2. The calling code C should have checked for success/failure, but doesn't.

  3. A non-existent resource or invalid information is used in code following C, causing general mayhem.

The main problem is point (2), where with the usual return code scheme the calling code C is not forced to check.

There are two main approaches that do force such checking:

  • Where P directly throws an exception when it fails.

  • Where P returns an object that C has to inspect before using its main value (otherwise an exception or termination).

The second approach was, AFAIK, first described by Barton and Nackman in their book *Scientific and Engineering C++: An Introduction with Advanced Techniques and Examples, where they introduced a class called Fallow for a “possible” function result. A similar class called optional is now offered by the Boost library. And you can easily implement an Optional class yourself, using a std::vector as value carrier for the case of non-POD result.

With the first approach the calling code C has no choice but to use exception handling techniques. With the second approach, however, the calling code C can itself decide whether to do if based checking, or general exception handling. Thus, the second approach supports making the programmer versus execution time efficiency trade-off.


What is the impact of the various C++ standards, on exception performance?

“I want to know is this still true for C++98”

C++98 was the first C++ standard. For exceptions it introduced a standard hierarchy of exception classes (unfortunately rather imperfect). The main impact on performance was the possibility of exception specifications (removed in C++11), which however were never fully implemented by the main Windows C++ compiler Visual C++: Visual C++ accepts the C++98 exception specification syntax, but just ignores exception specifications.

C++03 was just a technical corrigendum of C++98. The only really new in C++03 was value initialization. Which has nothing to do with exceptions.

With the C++11 standard general exception specifications were removed, and replaced with the noexcept keyword.

The C++11 standard also added support for storing and rethrowing exceptions, which is great for propagating C++ exceptions across C language callbacks. This support effectively constrains how the current exception can be stored. However, as far as I know that does not impact on performance, except to the degree that in newer code exception handling may more easily be used on both sides of a C language callback.

Costumier answered 12/12, 2012 at 12:49 Comment(30)
"exceptions is always slow compared to other basic operations in the language, regardless of the programming language"... except in languages designed to compile use of exceptions into ordinary flow control.Olmos
@BenVoigt: depends of course what you choose to view as "basic". for example, in Python even a simple integer assignment usually involves a dynamic memory allocation. still, an exception involves dynamic allocation plus a lot of other overhead. i think by "flow control" you're referring to the Python for loop. it's true that Python (the only language I know where "ordinary flow control" involves exception) is very slow, but all is relative: throwing an exception involves both allocation and stack unwinding, so cannot be faster than mere allocation. IOW., throw/raise involves much more.Costumier
@Alf: No, I mean languages where exceptions are dispatched statically. See for example https://mcmap.net/q/131550/-ocaml-performance-of-exceptions/103167Olmos
hm, Ocaml appears to be the exception that proves the rule. that said, i would put the emphasis on appears.Costumier
oh sorry, i forgot to say thanks for the ref. i didn't know that!Costumier
"exceptions is always slow compared to other basic operations in the language, regardless of the programming language". Last I looked, exceptions were around 6x slower using C++ than OCaml.Cartwright
@JonHarrop: use Ocaml for performance then (strange that it isn't a common choice).Costumier
@Cheersandhth.-Alf: I am indeed the downvoter. What you've written about "dynamic memory allocation" is also incorrect for the reasons I gave in my comment here that appears to have been deleted.Cartwright
"throwing an exception involves both allocation and stack unwinding". That is also obviously not true in general and, again, OCaml is a counter example. In garbage collected languages there is no need to unwind the stack because there are no destructors so you just longjmp to the handler.Cartwright
@JonHarrop: why do you persist in quoting out of context, and then making false claims about the context. a statement about Python does not apply to ocaml. ocaml is not a counter example to things not ocaml. by the way, both python and d are garbage collected languages where, with the common implementations at least, exception handling involves stack unwinding. that rather casts some doubt on the obviousness of "no need to unwind the stack", don't you think.Costumier
@"a statement about Python does not apply to ocaml". Ok, Stackless Python is obviously another counter example. I don't disagree that some specific Python implementation might do this but what you've written both in your answer and in the comments about stack unwinding and dynamic memory allocation is not generally true.Cartwright
@JonHarrop: each instance of the word "obvious" in your comments appear to identify a major fallacy. i have no idea what you think Stackless Python is counter-example of (maybe you think it has no stack?), and since you don't care to mention that, i certainly don't care enough to try to wrestle it out of you. i suspect that even you yourself don't know.Costumier
@Cheersandhth.-Alf: Stackless Python is another example of a language implementation that does not use stack unwinding. That is a counter example to your claim that throwing an exception involves stack unwinding. I am giving counter examples to various claims you have made both in your answer and in your comments. If you are interested in learning more I would suggest reading about these languages and their implementations because they don't solve these problems the way you say they are solved "In general, mostly regardless of language". C# are Java are also counterexamples re allocation.Cartwright
@JonHarrop: presumably you're unaware that Pyhon has a finally-clause for exception handling. this means a Python implementation either has stack unwinding or is not Python. you appear to be completely ignorant of the subjects that you make (fantasy) claims about. sorry.Costumier
@Cheersandhth.-Alf: "Pyhon has a finally-clause for exception handling. this means a Python implementation either has stack unwinding or is not Python". The try..finally construct can be implemented without stack unwinding. F#, C# and Java all implement try..finally without using stack unwinding. You just longjmp to the handler (as I already explained).Cartwright
@JonHarrop: I should have mentioned that executing finally blocks (including implicit ones in with statements) in stack frames up the call stack, on the way up to an exception handler, is a stack unwinding. And it's logically impossible to have stack unwinding without having stack unwinding. You're again talking nonsense, sorry.Costumier
@Cheersandhth.-Alf: Calling exception handlers isn't stack unwinding. That's exception handling. Stack unwinding means doing operations on a frame-by-frame basis as you go back up the stack to the next exception handler, such as calling destructors.Cartwright
@JonHarrop: you're seriously confused. also in your paraphrasing of what i've written, which, as your earlier comments, is self-contradictory nonsense. i'm giving up on you, sorry.Costumier
@Cheersandhth.-Alf: So you're still maintaining that Stackless Python either stack unwinds (even though it has no stack) or isn't Python (the clue is in the name)?Cartwright
@JonHarrop: "has no stack" is a nonsense misunderstanding on your part, taking the name literally. Any language that supports recursive routine calls has (in the sense of, must logically have, can't not have) a call stack. Again, I'm very sorry: this commentary field does not support the kind of extended discussion, with code examples etc., that's necessary to educate you. Also, I just don't have the time. Sorry.Costumier
So you are saying recursive calls always require a call stack?Cartwright
@JonHarrop: interpreting that in a good-faith way, then yes. interpreting it in incompetent's adversarial way, then no, it's only general support for recursive calls that requires a call stack. for one example, with a suitable low limit on the depth of recursion the calls can be inlined, and for another example, tail-recursion can often be optimized into a loop. i am guessing that you somehow have become aware of the last possibility i mentioned. but as i've mentioned already, i'm sorry, but this commentary field is not well-suited for educating you, nor should you rely on SO for learning.Costumier
@Cheersandhth.-Alf: "tail-recursion can often be optimized into a loop". In fact, an unbounded number of calls in tail position can always be optimised to use a bounded amount of stack space. Are you happy with that? cesura17.net/~will/professional/research/papers/tail.pdfCartwright
@JonHarrop: i don't have time for this, sorry. when i wrote "often", that was because in some cases other requirements, such as efficiency, can prevent tail-recursion optimization. for example, a simple tail-recursive C++ function that returns int may be optimized by Visual C++, while the same function except for return type double may not necessarily be so optimized, and then presumably for reasons of efficiency, which ties in to architecture from 1979 (the x87 math co-processor for handling floating point operations)... :(Costumier
@Cheersandhth.-Alf: Do you accept that an unbounded number of calls in tail position can always be optimised to use a bounded amount of stack space as described in the paper I am referencing? cesura17.net/~will/professional/research/papers/tail.pdfCartwright
@JonHarrop: i don't have time to help you properly with that. i would guess that "unbounded number of calls" is vague-speech for "unbounded recursion depth". but i would have to read the pdf to be sure, and maybe (even if the interpretation that i sketched can be meaningful) maybe it's just nonsense, as your earlier comments. instead of trying to memorize and get opinions about reliability of various autorities, i suggest you teach yourself by doing some programming. do recursion at the assembly level. do dynamic memory management at C or C++ level. then you can understand things. :-)Costumier
@Cheersandhth.-Alf: Do you accept that or not? Yes or no? cesura17.net/~will/professional/research/papers/tail.pdfCartwright
I realize this is old, but it seems like the entire argument above was based on one person who made a few statements that were general, because they knew that the name you give a data structure implies it's usage and abilities rather than it's implementation details.... While another person STRONGLY (too strongly if you ask me) feels that if you don't say the species of the duck, well then you might as well be calling it a goose? "Do you accept that you must call it a Mallard??? YOU MAY NOT CALL A MALLARD A DUCK PLUMED WHISTLERS ARE ALSO A DUCK."Pickar
I would normally avoid commenting on a post so old, but this is agonizing, and I did in fact learn at least one new thing while reading it all.. Seems a shame to leave it so stale with what if you boiled it off would be quite valuable information.Pickar
@Cheersandhth.-Alf Suppose a hypothetical language provides concise and cleaner syntax to write error-code base handling style, then which one would you prefer? error-code or exceptions?Playful
C
24

You can never claim about performance unless you convert the code to the assembly or benchmark it.

Here is what you see: (quick-bench)

The error code is not sensitive to the percentage of occurrence. Exceptions have a little bit overhead as long as they are never thrown. Once you throw them, the misery starts. In this example, it is thrown for 0%, 1%, 10%, 50% and 90% of the cases. When the exceptions are thrown 90% of the time, the code is 8 times slower than the case where the exceptions are thrown 10% of the time. As you see, the exceptions are really slow. Do not use them if they are thrown frequently. If your application has no real-time requirement, feel free to throw them if they occur very rarely.

You see many contradictory opinions about them. But finally, are exceptions are slow? I don't judge. Just watch the benchmark.

C++ exceptions performance benchmark

Colunga answered 26/9, 2018 at 8:53 Comment(1)
Thanks for putting this together. I re-ran it with a few different compiler choices and in each case it said that exceptions and error codes have equivalent performance for the "00" case. In my typical use cases that's the only that needs to be performant.Reimer
S
14

It depends on the compiler.

GCC, for example, was known for having very poor performance when handling exceptions, but this got considerably better in the past few years.

But note that handling exceptions should - as the name says - be the exception rather than the rule in your software design. When you have an application which throws so many exceptions per second that it impacts performance and this is still considered normal operation, then you should rather think about doing things differently.

Exceptions are a great way to make code more readable by getting all that clunky error handling code out of the way, but as soon as they become part of the normal program flow, they become really hard to follow. Remember that a throw is pretty much a goto catch in disguise.

Slack answered 12/12, 2012 at 8:52 Comment(9)
-1 re the question as it stands now, "is this still true for C++98", that certainly does not depend on the compiler. also, this answer's throw new Exception is a Java-ism. one should as a rule never throw pointers.Costumier
does the 98 standard dictate exactly how exceptions are to be implemented?Lit
C++98 is a ISO standard, not a compiler. There are many compilers which implement it.Slack
@thecoshman: No. The C++ standard says nothing about how anything should be implemented (with the possible exception of the "Implementation Limits" part of the standard).Peper
@Insilico then I can only draw the logical conclusion that (shockingly) it is implementation defined (read, compiler specific) how exceptions perform.Lit
@Alf: If you can point to the Standard section concerning exception performance, I'll agree with you. Otherwise, it's perfectly possible for conforming compilers to have very different performance, especially under the as-if rule, so it very much depends on the compiler.Olmos
@Ben: Andrei's talk was given in the summer of 2011. the current standard at that time was C++03. the C++98 standard was issued in 1998. was Andrei's point, assuming that it was true in 2011, "still true" in 1998? did that depend on the compiler? are you making sense?Costumier
@Alf: I agree the question is worded a little strangely. It could be read as "Is this also true when compiling in C++98 mode?" or "Was exception performance already much worse (than return value error reporting) in 1998?" And for both those questions, Philipp is quite correct that performance characteristics depend on choice of compiler. Many of the optimizations which Andrei says are disabled by the presence of exceptions may not have been prevalent; the relative costs of exceptions may well have been lower in 1998 for some compilers.Olmos
@BenVoigt: No, you're not making technical sense at all. The question "Is this [ungood performance] still true for C++98?" does not have the answer "It depends on the compiler". The answer is just untrue. The hypotheses about what the OP could have meant are disingenuous. And you knew that at the time of your comments.Costumier
S
0

In this simple benchmark I did just now, throwing exceptions is nearly 250x slower than a normal bool return code.

std::exception vs return code

Don't believe me. Try it yourself.

struct StopWatch {
  std::chrono::high_resolution_clock::time_point start;
  
  StopWatch() {
    reset();
  }
  
  void reset() {
    start = std::chrono::high_resolution_clock::now();
  }
  
  unsigned long long milli() const {
    std::chrono::high_resolution_clock::time_point stop = std::chrono::high_resolution_clock::now();
    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start);
    return ms.count();
  }
  
  double sec() const {
    std::chrono::high_resolution_clock::time_point stop = std::chrono::high_resolution_clock::now();
    return std::chrono::duration<double>(stop - start).count();
  }
};


const static int N = 1000000;

bool increase( char& counter ) {
  char prev = counter;
  counter++;
  return prev < counter; // false if overflow occurred
}

void increase_exc( char& counter ) {
  char prev = counter;
  counter++;
  if( prev > counter ) {
    // overflow occurred
    throw std::exception( "Overflow" );
  }
}

int main() {

  StopWatch timer;

  char count = 0;
  int errors = 0;
  for( int i = 0; i < N; i++ ) {
    if( !increase( count ) ) {
      errors++;
    }
  }
  double retCode = timer.sec();
  printf( "%d return code errors in %f seconds\n", errors, retCode );

  count = 0;
  errors = 0;
  timer.reset();
  for( int i = 0; i < N; i++ ) {
    try {
      increase_exc( count );
    }
    catch( std::exception& exc ) {
      errors++;
    }
  }
  double excTime = timer.sec();
  printf( "%d exception errors in %f seconds\n", errors, excTime );

  printf( "Exceptions are %.1fx slower than return codes", excTime / retCode );

}
Scone answered 10/4 at 0:41 Comment(0)
F
-2

Like in silico said its implementation dependent, but in general exceptions are considered slow for any implementation and shouldn't be used in performance intensive code.

EDIT: I'm not saying don't use them at all but for performance intensive code it is best to avoid them.

Fiddlewood answered 12/12, 2012 at 8:46 Comment(3)
This is at best a very simplistic way of looking at exception performance. For example, GCC uses a "zero-cost" implementation where you don't incur a performance hit if no exceptions are thrown. And exceptions are meant for exceptional (i.e. rare) circumstances, so even if they are slow by some metric that's still not enough reason to not use them.Peper
@insilico if you look at why I said, I did not say not to use exceptions full stop. I specified performance intensive code, this is an accurate assessment, I mainly do work with gpgpus and I wud be shot if I used exceptions.Fiddlewood
I don't think your answer is strictly wrong, but I can understand why people voted it down as it is not particularly informative. Leaves a lot more questions than answers, and could give the wrong impression to a more naïve reader.Garrulous

© 2022 - 2024 — McMap. All rights reserved.