Its unrolling the stack, whatever could go wrong?.. Its only expensive when you throw an exception.
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. Another cost is having to track which base classes of a derived class have already been constructed when the derived constructor throws. You get noticeably better generated code when the compiler can skip all that junk.
> 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.
Thanks for holding the discussion to exact standards. What I meant about the base class constructors is the compiler must generate a derived-class constructor that can unwind the completely constructed base in case the derived class throws, not to mention the ability to destroy constructed subobjects with non-trivial destructors in case one of _their_ constructors throws. When your project decides to outlaw exceptions then none of these events are even possible and the compiler will generate a much more compact and infallible 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.
Ah, yes, I wasn't thinking about throws during destructors. IIRC, that's considered bad form but not forbidden, and so a compiler would have to handle that. (Feel free to correct if I have that wrong.)
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.
Throwing during destructors will generally result in a std::terminate, since you have good odds of throwing during destruction of an object that is being cleaned up as a result of an existing in progress exception.
So it is not forbidden but odds are you'll have your program terminate.
while there is extra code, there should be no extra branches in the successful case. The exceptional code path is reached during unwind by comparing the IP of the throwing call with a per stack frame table (recursively walking up the stack). Also the extra code will be extremely cold, at the limit not even paged in from disk (which of course might make the first time an exception is thrown an explicit path extremely costly)
The compiler has to generate code that works when exceptions are thrown. This limits some optimizations and adds overhead even if nothing happens at runtime.
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.