Investigating the Performance Overhead of C++ Exceptions
Exceptions are not meant to be fast. In fact, exceptions are meant to be exceptional. Hence the name.<p>Exceptions are meant to be fast if and only if you do not throw any. And even this is only truly true on Unix.<p>The original implementation of exceptions on Windows put extra unrolling info on the stack and then cleaned it up at the end of the function, adding a runtime cost even when no exceptions were thrown.<p>The Unix way of exception handling does not put anything extra on the stack, so exceptions are free if you don&#x27;t throw any. The compiler puts some metadata into your binary and generates cleanup code. If an exception is thrown, the run-time (libstdc++ for gcc on Linux) will grab the return address from the stack and then do a binary search through the metadata to find the right unwinding code generated by the compiler. This is obviously a comparatively enormous overhead. In particular because the metadata are separated from the code, so the OS never has to read it from disk unless you actually throw an exception.<p>The reason for that is that you are not supposed to use exceptions for signaling. They are for error handling. Exceptions are for occasions like &quot;you asked for memory but there was none left&quot; or &quot;you asked for the 15th element in this vector but it only has 10&quot;. They are not meant for non-exceptional errors like &quot;you asked for data from the network but there is no data yet&quot; or &quot;you wanted me to check if the file exists and it does not&quot;.<p>The thinking behind all this is that the error handling path is not time critical. If it happens, something exceptional has happened, and the OS will probably have to swap in the error handling code from disk to begin with, which is horrendously slow. In fact, this is not just a possibility. The feature was designed specifically so that the linker would move the exception handling code to a different page and the OS would only read that page from disk if an exception actually occurs. This is not an accident. It is deliberate planning and took engineering effort to achieve.<p>Running a benchmark of throw vs return is an attempt to answer the wrong question.<p>Important side note: operator[] on a vector does not do range checking. at() does. That&#x27;s why you should always use at() instead of operator[].