I don't know about NASA's case, but Google's style guide forbids exceptions only for legacy reasons. In fact it praises them:
"On their face, the benefits of using exceptions outweigh the costs, especially in new projects. However, for existing code, the introduction of exceptions has implications on all dependent code. ... Because most existing C++ code at Google is not prepared to deal with exceptions, it is comparatively difficult to adopt new code that generates exceptions."
Since I'm not working on Google's old code base I do use exceptions.
> 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.
'zero-overhead' for some feature is equal to 'no runtime overhead above what one would incur from coding the feature yourself.
That definition explicitly does not include the concept that 'zero-overhead' features carry no cost when not used. In fact, the entire point of Bjarne discussing what "zero-cost" means in his response to Sutter's exception proposal, is to state that for C++ (which originated the term) "zero-cost"/zero-overhead does not mean that language features do not incur cost by inclusion in the language, like with exceptions. There is a cost to code during runtime if one does not explicitly remove exceptions from the language at compile time. Stroustrup's point is that this built in runtime overhead from having an exception mechanism built into C++ does not violate the language's 'zero-cost' guarantee.
"What you don’t use, you don’t pay for. And further: What you do use, you couldn’t hand code any better."
Ideally I would like to use exceptions as well, since they make the code look a lot neater and clearer, but I cannot justify their use in all places because of these non-zero costs.
The time to run exceptions is a lot less than to run failure checks, except in extreme cases as in the synthetic (not to say phony) benchmark presented. If the time spent throwing matters, you're Doing It Wrong.
The branch prediction slots that failure checks burn are rare and precious: much bigger than a general purpose register, and much faster than L1 cache. Blowing your branch prediction cache has costs hard to measure, although the perf registers help some.
The only substantial cost is object-code file size, and that mainly because precious little effort has been spent to minimize it, because really hardly anybody (i.e., only embedded) cares.
The problem with proving something like this is you have to build and maintain two separate sets of code for the same project, one that uses exceptions in the correct manner, and another which does error checking to the same degree. Nobody has time to do that for a significant project.
ETA: an uncontended mutex lock takes around 10-30ns depending on the machine. Any kind of exception is far more costly.
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.
Then the program can do whatever cleanup is warranted, maybe freeing up a variety of other resources, and then maybe re-reserve that block, and forge ahead.
But when you actually care about performance, you often are not using the global allocator. A local allocation failure is nothing to panic over. Generally, only the higher level code -- where the handler is -- knows, or needs to care, what kind of allocator failed. The low-level code gets to just bail out, as it should.
And there are plenty of other root causes for exceptions in real programs, not just allocations.
That does not mean one needs exceptions, though.
Herb Sutter is, reliably, always right on his facts, but always mistaken on his opinions.
They should only be used in exceptional circumstances, but they appear to be littered among libraries for everything from telling the caller that the end of file has occurred to a connection timing out.
> The cost comes from having to track what automatic and temporary objects have been created and attaching them to the exception context so you can destroy them if an exception is thrown.
Doesn't it have to do that anyway, in case you return from a function, or break from inside a loop? Anytime you can leave a scope, it has to be able to do that.
> Another cost is having to track which base classes of a derived class have already been constructed when the derived constructor throws.
All of them have been constructed before you begin the derived constructor.
As for leaving the scope, you're right again and I was unclear. The problem is you are destroying automatic objects while returning from a scope and one of them throws. Now you have extra code and extra branches for all of that. The extra ways of exiting a scope generally bloat up the program, and the size and complexity of a function can prevent it from being inlined or otherwise optimized by the compiler. These are systemic performance concerns that won't just show up as hot spots on a profile.
As to your first paragraph: That's just calling the base class's destructor if the derived class's constructor throws. That's easy - that's what the base class's destructor is for. It's essentially one function call. The harder part (or so it seems to me) is correctly destroying the only-partially-constructed derived class.
So it is not forbidden but odds are you'll have your program terminate.
https://github.com/CppCon/CppCon2014/blob/master/Presentatio...
Instead of having a Constructor + init method you could have a static create function which returns an optional or a pair.
I have a hard time seeing in what case you would want to throw in a destructor though? Maybe I'm just writing a different kind of code :)
I can't imagine that case either - but what I can imagine is that your destructor calls a function that calls a function ... that calls a function you didn't realize can throw.
Point being it's not entirely orthogonal to "performance".
However value type exceptions might re-introduce it, just in a different form, with luck on C++23.
I'm a huge fan of checked exception, given a type system powerful enough to parametrize over them (C++ should be more than capable), so I'm looking forward to the development. Stroustrup is not a fan though and he might kill the effort.