the slower generated code is an academic concern. Show me a realistic/non-contrived benchmark where not keeping the stack unwindable actually helps give a useful performance increase. Error codes force people to litter the code with branches and put error handling code in the hot path of the instruction stream.
Using 'likely/unlikely' compiler directives, the instructions in the unlikely error branch can be hoisted out to another area and not significantly affect instruction cache. It still is a branch though.
and exception-based code can have much less branches since you don't need to check every function call for error but instead let the exception propagate from where they can be thrown. e.g. in a hypothetic case where you load a settings file five layers deep, in an error-code-based solution you have potentially 5 branches while in an exception-based solution you only have one
At the cost of predictable performance though. With current implementations, the exceptional path will be several magnitudes (!) slower for cheap functions.
Exceptions impose indirect costs other than just code size. For example, when std::vector reallocates, it copies instead of moves its elements, in case the move constructor throws and leaves the vector in an inconsistent state.