How to Disable Exceptions in Stl

Disabling C++ exceptions, how can I make any std:: throw() immediately terminate?

Option #1: Simply never catch exceptions.

Exceptions don't have much overhead when they're not thrown or caught; if you're throwing and not prepared to catch, well, you're doing to die anyway, so the performance impact at that point is trivial. Note also that stack unwinding will not be performed if an exception is not handled; the program will simply terminate without performing stack unwinding.

It's important to note that, in G++, exceptions have almost no overhead when not actually thrown. G++ generates extra information sufficient to trace back the execution of the program through the stack, and some extra code to invoke destructors, etc - however none of this extra code or data is ever used until an exception is actually thrown. So you should not see a performance difference between code with exceptions enabled but not used and code with exceptions disabled (through whatever mechanism).

Option #2: Pass -fno-exceptions.

This flag instructs G++ to do two things:

  1. All exception handling in STL libraries are removed; throws are replaced with abort() calls
  2. Stack unwind data and code is removed. This saves some code space, and may make register allocation marginally easier for the compiler (but I doubt it'll have much performance impact). Notably, however, if an exception is thrown, and the library tries to unwind through -fno-exceptions code, it will abort at that point, as there is no unwind data.

This will, effectively, turn all exceptions into abort()s, as you would like. Note, however, that you will not be allowed to throw - any actual throws or catchs in your code will result in a compile-time error.

Option #3: (Nonportable and not recommended!) Hook __cxa_allocate_exception.

C++ exceptions are implemented using (among others) the __cxa_allocate_exception and __cxa_throw internal library functions. You can implement a LD_PRELOAD library that hooks these functions to abort():

void __cxa_allocate_exception() { abort(); }
void __cxa_throw() { abort(); }

WARNING: This is a horrible hack. It should work on x86 and x86-64, but I strongly recommend against this. Notably, it won't actually improve performance or save code space, as -fno-exceptions might. However, it will allow the throw syntax, while turning throws into abort()s.

How to turn off exceptions in Microsoft compiler(cl)?

In your project properties set the Enable C++ Exceptions to No:
Disable C++ Exceptions

and enable the unwind semantics by specifying the /EHsc flag:
Unwind semantics

To set this option on command line you would leave out the /EHa, /EHsc and /EHs flags from the [option] section as described in the Compiler Command-Line Syntax manual.
Further relevant MSDN reading:

  • /EH (Exception Handling
    Model)
  • Compiler Options Listed by
    Category
  • Setting Compiler
    Options

Handling STL errors without exceptions

The problem with taking an existing std library coontainer and compiling with exceptions disabled is that the the std container interfaces themselves assume exceptions are enabled. Using exceptions, operator new will throw if it cannot acquire memory, without exceptions, operator new returns a 0 instead, which std containers cannot handle.

One approach is to only use STL algorithms + vector. You can replicate about 95% of what the other containers do using this. The problem is that most STL implementations assume that

v.reserve(v.size()+1);
assert(v.size()+1<=v.capacity());

will never assert (since reserve will throw if there is no memory). To insure this never throws, I have used "fixed capacity" containers, i.e. containers with a capacity fixed at compile time. Basically these are vectors where I pass in a special allocator. Then you can check the max_size() of the container before insertion. Then just avoid using things like at(). For even better predicatbilty, use basic_string instead of vector. This forces you to only store POD types, which never throw when copied or default constructed. Plus memory requirements are easier to compute.

Another approach is to use intrusive containers. These don't throw (outside of misuse of the interface perhaps), since they never acquire memory in the first place.

If you're in the we don't use exceptions camp, then how do you use the standard library?

I will answer for myself and my corner of the world. I write c++14 (will be 17 once compilers have better support) latency critical financial apps that process gargantuan amounts of money and can't ever go down. The ruleset is:

  • no exceptions
  • no rtti
  • no runtime dispatch
  • (almost) no inheritance

Memory is pooled and pre-allocated, so there are no malloc calls after initialization. Data structures are either immortal or trivially copiable, so destructors are nearly absent (there are some exceptions, such as scope guards). Basically, we are doing C + type safety + templates + lambdas. Of course, exceptions are disabled via the compiler switch. As for the STL, the good parts of it (i.e.: algorithm, numeric, type_traits, iterator, atomic, ...) are all useable. The exception-throwing parts coincide with the runtime-memory-allocating parts and the semi-OO parts nicely so we get to get rid of all the cruft in one go: streams, containers except std::array, std::string.

Why do this?

  1. Because like OO, exception offers illusory cleanliness by hiding or moving the problem elsewhere, and makes the rest of the program harder to diagnose. When you compile without "-fno-exceptions", all your clean and nicely behaved functions have to endure the suspicion of being failable. It is much easier to have extensive sanity checking around the perimeter of your codebase, than to make every operation failable.
  2. Because exceptions are basically long range GOTOs that have an unspecified destination. You won't use longjmp(), but exceptions are arguably much worse.
  3. Because error codes are superior. You can use [[nodiscard]] to force calling code to check.
  4. Because exception hierarchies are unnecessary. Most of the time it makes little sense to distinguish what errored, and when it does, it's likely because different errors require different clean-up and it would have been much better to signal explicitly.
  5. Because we have complex invariants to maintain. This means that there are code, however deep down in the bowels, that need to have transnational guarantees. There are two ways of doing this: either you make your imperative procedures as pure as possible (i.e.: make sure you never fail), or you have immutable data structures (i.e.: make failure recovery possible). If you have immutable data structures, then of course you can have exceptions, but you won't be using them because when you will be using sum types. Functional data structures are slow though, so the other alternative is to have pure functions and do it in an exception-free language such as C, no-except C++, or Rust. No matter how pretty D looks, as long as it isn't cleansed of GC and exceptions, it's an non-option.
  6. Do you ever test your exceptions like you would an explicit code path? What about exceptions that "can never happen"? Of course you don't, and when you actually hit those exceptions you are screwed.
  7. I have seen some "beautiful" exception-neutral code in C++. That is, it performs optimally with no edge cases regardless of whether the code it calls uses exceptions or not. They are really hard to write and I suspect, tricky to modify if you want to maintain all your exception guarantees. However, I have not seen any "beautiful" code that either throws or catches exceptions. All code that I have seen that interacts with exceptions directly have been universally ugly. The amount of effort that went into writing exception-neutral code completely dwarfs the amount of effort that was saved from the crappy code that either throws or catches exceptions. "Beautiful" is in quotes because it is not actual beauty: it is usually fossilized because editing it requires the extra burden of maintaining exception-neutrality. If you don't have unit tests that deliberately and comprehensively misuse exceptions to trigger those edge cases, even "beautiful" exception-neutral code decays into manure.


Related Topics



Leave a reply



Submit