4 ms·
A couple of misconceptions here: > It should be well-known that actually throwing an exception in C++ is extremely costly. Unfortunately it is well known, but
by quietbritishjim 7y ago
A couple of misconceptions here:
> It should be well-known that actually throwing an exception in C++ is extremely costly.
Unfortunately it is well known, but without really understanding what "extremely costly" means. The article shows it is expensive compared to returning from a function that does almost nothing. But what about compared to allocating some memory? Or locking a mutex? Just recently here on Hacker News I recently saw someone worryung about using an exception to close a file after doing a bunch of reads because they thought it would be too slow – but, in reality, the time taken to read a whole file is astronomical compared to throwing an exception.
> C++'s "zero-overhead" principle
Now it's possible you're right here, but just to be clear: this principle just means features don't have a cost if you don't use them. For example, if you don't need a function to be virtual then you don't have to mark it as such, so the fact that C++ supports virtual methods didn't cost you anything. But if you do choose to mark a method as virtual then there will be costs involved (memory will be taken up with the vtable and pointers to it, invocations through a pointer will take longer). Similarly, the fact that throwing exceptions isn't zero cost does not violate this principle.
The reason I say you could still be right is that there is still a memory cost to including tables of unwinding information for exceptions even if you never throw them. Perhaps that's what you meant, but the surrounding text seems to be hinting at the cost of throwing them.
- thedance 7y agoExceptions being contrary to zero-overhead is not something that is just my opinion. Here's Herb Sutter's detailed white paper on the topic: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0709r1.pdf http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p070... ETA: an uncontended mutex lock takes around 10-30ns depending on the machine. Any kind of exception is far more costly.
- qeqeqeqe 7y agoBjarne Stroustrup wrote a rebuttal to that proposal http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1947r0.pdf http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p194...
- thedance 7y agoStroustrup constructs a bit of a false dichotomy there. He presents the choice between exceptions and explicit error propagation and checking, but there is a third way. If the allocator is simply infallible and std::bad_alloc just doesn't exist, and the program terminates on allocation failure instead, then you need neither exceptions nor error codes. Since std::bad_alloc is such a prominent root cause of all exceptions, and since it's preposterous to believe a program can continue after the global allocator stops working, this turns out to be a dramatic simplification of the overall program. Once you get rid of allocator exceptions it's not a big mental leap to just decide to get rid of all of them.
- jfkebwjsbx 7y agobad_alloc does not mean the allocator has stopped working. It only means that a particular allocation cannot be served. And there are plenty of other root causes for exceptions in real programs, not just allocations. That does not mean one needs exceptions, though.
- usrnm 7y agoBut std::bad_alloc does exist and it's possible and sometimes necessary to write correct software that's able to handle allocation errors. What we probably need is some sort of a compiler switch, but it will significantly complicate writing generic multi-purpose libraries
- thedance 7y agobad_alloc doesn't just naturally spring into being. If you override operator new, your implementation may not use it (for example tcmalloc does not throw if it can't allocate, it logs a message and terminates the program). Many systems of the type you mention, embedded control systems and the like where correctness actually matters, don't use new and delete anyway. They often use placement new with space statically allocated at program startup. These are the same kinds of projects that often decide to not use exceptions.
- ncmncm 7y ago
- ncmncm 7y agoContended mutex locks, of course, may take far, far longer than 30ns, and 30 nanoseconds is an eternity, enough time to run 500 instructions on a modern CPU. Herb Sutter is, reliably, always right on his facts, but always mistaken on his opinions.
- quietbritishjim 7y ago> an uncontended mutex lock takes around 10-30ns depending on the machine. I am grateful for this. But I do wish the article had a few more comparisons like this, up to and including things much more expensive than exceptions, so readers could make their own decisions rather than just read about how terrible exceptions are. As another data point, I just read that a Linux system call that does no actual work takes about 250ns, so about a fifth of the time for an exception from the article. Of course that's a totally unknown machine that could be much slower or faster than the one used for the article's benchmark. But I still found it interesting that they're the same order of magnitude – I hadn't expected exceptions to be quite that slow.
- je42 7y agoHerb Sutter also has presentation on this: https://www.youtube.com/watch?v=ARYP83yNAWk https://www.youtube.com/watch?v=ARYP83yNAWk
- throwaway17_17 7y agoI think qualification of statements is in order. I have heard the definition you gave for ‘zero-overhead’ abstractions in several places. Basically, it is often described as features which impose no cost when they are not used. However, Stroustrup uses and advocates another definition, which he discusses in his response to Sutter’s exception proposal linked by a sibling comment. When Bjarne says ‘zero-cost’ he means that some feature incurs no overhead in comparison to equivalent functionality which is hand coded. These two definitions are not equal, Bjarne’s definition (which as the originator of the term [or so I’ve heard], I tend to use as the correct case) is only concerned with asserting the overhead of language constructs compared to specific implementations of the same functionality. There is no requirement that those abstractions and features have no impact on the produced machine code or runtime requirements of not used. I wish zero-overhead meant what you say it means, but it clearly doesn’t.
- quietbritishjim 7y agoInteresting, thanks. I thought I got my definition from Design and Evolution of C++ by Stroustrup but it's a very long time since I read it. (It's also possible that Stroustrup has used that term in different ways over the years, but it's much more likely that I'm just mistaken.)
- throwaway17_17 7y agoI think your memory is correct and that Bjarne has probably been loose with the term, I’ll check just to satisfy my curiosity later, but I do know he has been using the version I mentioned several times in the last few years.
- ncmncm 7y agoSome abstractions have no overhead under any circumstances, others have no runtime cost if not used. It is not inconsistent to include the former, trivially.
- 7y ago