40

In When to use C over C++, and C++ over C? there is a statement wrt. to code size / C++ exceptions:

Jerry answers (among other points):

(...) it tends to be more difficult to produce truly tiny executables with C++. For really small systems, you're rarely writing a lot of code anyway, and the extra (...)

to which I asked why that would be, to which Jerry responded:

the main thing is that C++ includes exception handling, which (at least usually) adds some minimum to the executable size. Most compilers will let you disable exception handling, but when you do the result isn't quite C++ anymore. (...)

which I do not really doubt on a technical real world level.


Therefore I'm interested (purely out of curiosity) to hear from real world examples where a project chose C++ as a language and then chose to disable exceptions. (Not just merely "not use" exceptions in user code, but disable them in the compiler, so that you can't throw or catch exceptions.) Why does a project chose to do so (still using C++ and not C, but no exceptions) - what are/were the (technical) reasons?


Addendum: For those wishing to elaborate on their answers, it would be nice to detail how the implications of no-exceptions are handled:

  • STL collections (vector, ...) do not work properly (allocation failure cannot be reported)
  • new can't throw
  • Constructors cannot fail
Martin Ba
  • 7,578
  • 7
  • 34
  • 56
  • 1
    JSF C++. Jets and exceptions don't mix. – Coder Jun 02 '12 at 21:24
  • 1
    Some enlightening info about problems with exceptions (and C++ in general) http://www.250bpm.com/blog:4 – Ambroz Bizjak Jun 03 '12 at 22:41
  • 1
    @AmbrozBizjak - I'll quote DeadMG from a comment to the post you link to: quote:"It appears to me that you do not understand exceptions." I agree. The author clearly made a mess of exception handling, looking at the examples he gives in that post. – Martin Ba Jun 04 '12 at 09:13

11 Answers11

35

Almost any console game out there is in C++ with exception deactivated, even today. In fac it's the default setup for C++ compilers targeting those consoles. Sometimes some C++ features are not guaranteed to work correctly on those compilers, like multiple inheritance (I'm thinking about a very well known console default compiler for example).


Also, another example is Arduino hardware SDK usnig gcc without exception activated in C++, and other things like no STL provided.


There are some technical reasons, good or bad, whatever, it's not my advice but reasons I've heard :

  1. Most consoles are really embedded systems with limited memory and processing time. Maybe it will not be so true in future consoles, but current ones are still prety restrictive compared to a PC. Some portable consoles are erally harder to program than any smartphone, for example the NDS. Exception feature does add memory and a little bit of speed cost, even if you don't use it. You can check yourself, it's true even on PC.
  2. Video games on console can't crash. They have to be tested in a way that avoid any crash or any dead-end, any showstoper. That's why console manufacturers asks the games to be heavily checked before publication. That also mean that exception management add cost that isn't really useful in case of console game. It's better in smartphone for example because there might be some ways to recovery or the add some code to email you the problem. Closed platforms like most consoles don't allow this. So an exception system isn't really necessary after all. You "just have to make it work correctly". ;)
  3. Exception management, when you don't allow errors and crashes, means you have to implement an error management strategy. Such system might be complex enough to make someone work a lot of time to make it useful. Game developers don't have luxury to work on features that are thought to be useful in crashes...
  4. The compiler don't allow it (yet). Yes, it happen.

I think exceptions can be useful even in games but that's truee that on console games it's not really useful.


Update:

I'm adding another surprising example here: LLVM/CLang dont use exception nor RTTI for the followin reasons:

In an effort to reduce code and executable size, LLVM does not use RTTI (e.g. dynamic_cast<>) or exceptions. These two language features violate the general C++ principle of "you only pay for what you use", causing executable bloat even if exceptions are never used in the code base, or if RTTI is never used for a class. Because of this, we turn them off globally in the code.

That said, LLVM does make extensive use of a hand-rolled form of RTTI that use templates like isa<>, cast<>, and dyn_cast<>. This form of RTTI is opt-in and can be added to any class. It is also substantially more efficient than dynamic_cast<>.

CLang is well known for its speed ofr compilation and explicit errors, but also its one rare compiler that have really easy-to-follow code.

chrisaycock
  • 6,655
  • 3
  • 30
  • 54
Klaim
  • 14,832
  • 3
  • 49
  • 62
  • 9
    (3): you need an error management strategy no matter what, if you're going to go along with (2). Problems will come up, and your console software needs to fail soft and gracefully. It isn't obvious to me that avoiding exceptions entirely makes that any easier. – David Thornley Oct 10 '11 at 16:37
  • 6
    All great examples of tightly controlled runtime environments where errors are handled properly and there are no "exceptional" events. – Patrick Hughes Oct 10 '11 at 16:42
  • 1
    @DavidThornley Because you assume that the console's system will manage some kind of errors, but it will not. Well maybe it will on PS3 or XBox but that will not be allowed to pass console builder's tests. Anyway, the firmware of most advanced consoles isn't as flexible as you might think. A console game need to have access to almost all the hardware of the console, so you can think about a game running on a console almost like if it was also the "OS" of the console... the more we have powerful consoles, the less it is true. So I agree with you that it seems strange for some cases. – Klaim Oct 10 '11 at 16:45
  • Yet, it's classic in video game console developpement. – Klaim Oct 10 '11 at 16:46
  • @Klaim: I'm confused. In your second point, you said that failures were not an option. In your comment, you said the system won't handle certain kinds of errors. If it can't handle a certain sort of error, what does it do? It will encounter power glitches, connectivity glitches, and the occasional software error. You need a strategy, and you haven't given any reasons why exceptions make that more complicated. I'm disagreeing with your point 3 here, not the rest of your reasons. – David Thornley Oct 10 '11 at 17:26
  • What I mean is that only advanced systems like Xbox360 and PS3 will handle a crash by... stopping the game. It will not apply any other strategy to manage the fact that there have been an error somewhere. Other consoles will just "freeze", mostly because there is no firmware running in the background once the game is launched. Also, I personally agree with your disagreement, still it's a point taken as valid by the gaming industry. Also, game dev is a lot about implementing very complex systems interacting with each others so any additional system have a cost in developpement too. – Klaim Oct 10 '11 at 17:43
  • Exceptions are a very slow error handling mechanism because they are so generic and flexible. Not using exceptions, but still handling errors with your own logic is almost always faster simply because (from necessity) the exception throw/catch mechanism is very heavyweight and anti-performance. Incidentally exception handling works on both PS3 and 360 afaik... you can even catch floating point exceptions with a little effort on PS3 which can be invaluable for tracking down QNaNs. – jheriko Oct 10 '11 at 18:48
  • Incidentally multiple and even virtual inheritance works fine with every console compiler from the current generation that I know about... – jheriko Oct 10 '11 at 18:50
  • +1 for arduino example. Atmel8 is an astoundingly constrained platform; some don't even have *stack pointers*, but you can still use a reasonable, limited subset of C++! – SingleNegationElimination Oct 10 '11 at 19:07
  • @jheriko> I think most companies will not use exception on xbox360 and ps3 anyway just because of history, knowledge about their use and the fact that they still need to make something that "never crashes". But I think it will change will better platforms. I know it's just impossible to use exceptions on NDS without hurting a lot on memory. – Klaim Oct 10 '11 at 22:12
  • 2
    This is a good answer, I'd like to also add that even if an exception bubbled up and presented the user with an error, what is he or she supposed to do about it with a D-pad? The only real solution for the end user is a restart. – anon Oct 11 '11 at 02:34
  • 2
    I removed the folly example because someone on their team said on boost the NO EXCEPTION is not meant to mean "no use of exception" but "no exception to the rules". See http://permalink.gmane.org/gmane.comp.lib.boost.devel/231377 – Klaim Jun 04 '12 at 17:58
9

Jerry said: ...the result isn't quite C++ anymore, while my metaphor is that it is clearly C++, just a slightly different dialect because programs utilize other forms, conventions, and written styles.

Here are my primary reasons for disabling them:

Binary Compatibility

Crossing language and translation boundaries is not universally well defined, or undefined. If you want to guarantee your program operates within the domain of defined behavior, you will need to quarantine exceptions at module exit points.

Executable Size

Here are the binary sizes of an exception free program I wrote, built without and with exceptions enabled:

Without exceptions:

  • executable + dependencies: 330
  • final stripped executable (release build): 37

With exceptions:

  • executable + dependencies: 380
  • final stripped executable (release build): 44

Reminder: That's a collection of libraries and programs which contain zero throws/catches. The compiler flag does enable exceptions in the C++ standard library. Therefore, the cost in the real world is more than 19% seen in this example.

Compiler: apple gcc4.2 + llvm. Sizes in MB.

Speed

Despite the term "zero cost exceptions", they still add some overhead even when nothing ever throws. In the above case, it is a performance critical program (Signal Processing, Generation, Presentation, Conversions, with large data sets/signals etc.). Exceptions are not a necessary feature in this design, while performance is very important.

Program Correctness

Seems like a strange reason... If throwing is not an option, you must write relatively strict, correct, well tested programs to guarantee your program executes correctly, and that clients use the interfaces correctly (if you give me a bad argument or do not check an error code, then you deserve UB). The result? Implementation quality improves greatly and problems get fixed quickly.

Simplicity

Exception handling implementations aren't often kept up to date. They also add a lot of complexity because an implementation can have many many many exit sequences. It's simpler to read and maintain highly complex programs when they use a small set of well defined, typed, exit strategies which bubble up to and are handled by the client. In other cases, the implementations may over time implement more throws or their dependencies may introduce them. Clients cannot easily or appropriately defend against all these exits. I write and update a lot of libraries, there is frequent evolution and improvement. Attempting to keep that all in synch with exception exit sequences (in a large codebase) would not be a good use of time, and would likely add a lot of noise and cruft. Due to increased program correctness and more tests, many (certainly not all) of the potential issues/exits can be ruled out.

History/Existing Code

In some cases, they were never introduced for historical reasons. An existing codebase did not use them, changing the programs could take man-years and make it really ugly to maintain because of overlap in conventions and implementations.

Downsides

Of course, there are downsides, the biggest are: Incompatability (incl. binary) with other libraries, and the fact that you will have to implement a good amount of programs to fit this model.

justin
  • 2,023
  • 1
  • 17
  • 15
  • +1 excellent info! (although I do not agree with the Simplicity paragraph) – Martin Ba Oct 11 '11 at 08:56
  • It would be interesting if you only have no-fail constructors and how you handle allocation (- failure). – Martin Ba Oct 11 '11 at 08:58
  • @Martin 1) Disagreeing is quite fine. I understand that most devs disagree with disabling exceptions for multiple reasons. For simplicity, it goes along with program correctness. Problems/invalid states simply aren't allowed to travel far. That means they check for failures and exit gracefully. jheriko's post echoes this. – justin Oct 11 '11 at 09:08
  • @Martin 2) *Some* constructors can still fail, but those are discouraged. For a result code, it takes this basic form: `t_object(t_result_code& outError /* more arguments */);` – justin Oct 11 '11 at 09:12
  • 1
    @Martin 2b) allocation is a bit more complex. First, the number of heap allocations is reduced in number and increased in size - there relatively few heap allocations to begin with. Second, allocations go through custom allocators. If an allocation is not initially provided for the allocator (e.g. `malloc` returns `0`), the allocator enters a `while (1)` which has a context switch, followed by another attempt at allocation. In this codebase, it used to be that new via the allocator could return 0, but the newer implementation has been working fine. (cont) – justin Oct 11 '11 at 09:20
  • (cont) The allocators also assert if an insane request is made (e.g. in the event of undetected overflow), as well as several other checks. In that case, an assertion is hit in debug mode if something seems wrong. It's not 100% foolproof in release, but the probability is tiny (it's been tested well in a variety of programs, such that system libraries' failure rates are definitely on the radar as well) and there will be some logging attempts if such a failure is encountered in release. – justin Oct 11 '11 at 09:27
  • so you use customn allocators for the STL containers and just accept that a very tiny percentage of allocation errors will abort the program? - do I understand correctly? – Martin Ba Oct 11 '11 at 09:39
  • 2
    yes, there is a stl compatible wrapper over the custom allocator interfaces. technically, the program will not abort in release; it will introduce context switches (e.g. allow another thread to work which will hopefully free some memory), retry, and log if that fails - forever. unit tests can run for days without issue. the only real threat is huge allocations, many of which will be caught before requested. again, the system's failure rates are also on the radar at this point; the possibility exists that they will fail before the core implementation in such a scenario. – justin Oct 11 '11 at 10:00
  • Let me note that I've worked on a system that introduced exceptions into a many-years-old C program. It was NOT a good idea. That decision produced almost as many errors in the system as having changed from a co-operative threading model to a pre-emptive one with no pre-planning. – Michael Kohne Oct 12 '11 at 13:19
7

Google doesn't approve of exceptions in their C++ Style Guide, mostly for historical reasons:

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. If exceptions can be propagated beyond a new project, it also becomes problematic to integrate the new project into existing exception-free 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.

Given that Google's existing code is not exception-tolerant, the costs of using exceptions are somewhat greater than the costs in a new project. The conversion process would be slow and error-prone. We don't believe that the available alternatives to exceptions, such as error codes and assertions, introduce a significant burden.

Our advice against using exceptions is not predicated on philosophical or moral grounds, but practical ones. Because we'd like to use our open-source projects at Google and it's difficult to do so if those projects use exceptions, we need to advise against exceptions in Google open-source projects as well. Things would probably be different if we had to do it all over again from scratch.

There is an exception to this rule (no pun intended) for Windows code.

(Editor's emphasis)

Macke
  • 2,576
  • 16
  • 16
SuperElectric
  • 1,931
  • 2
  • 13
  • 9
5

Qt almost never uses exceptions. Errors in Qt are signified with error codes and signals. The officially stated reason is:

When Qt was started exceptions were not available for all the compilers that needed to be supported by Qt. Today we are trying to keep the APIs consistent, so modules that have a history of not using exceptions will generally not get new code using exceptions added.

Why does QT use so few exceptions?

Today, one common criticism of Qt is that its exception safety is not complete.

user16764
  • 3,583
  • 1
  • 25
  • 22
  • 1
    Thanks. Good info, although I'm wondering whether most QT code bases probably have exceptions enabled in the compiler ... – Martin Ba Jun 03 '12 at 12:44
4

Symbian C++ (used on some Nokia mobile phones) doesn't use exceptions, at least not directly, because C++ compilers didn't reliably implement them when Symbian was first developed.

Keith Thompson
  • 6,402
  • 2
  • 29
  • 35
  • 1
    This doesn't hold for modern versions of Symbian. [Symbian TRAPs and leaves are implemented as real C++ exceptions](http://www.developer.nokia.com/Community/Wiki/Fundamentals_of_Symbian_C%2B%2B/Leaves_%26_The_Cleanup_Stack#Mixing_Leaves.2C_Exceptions_and_the_Cleanup_Stack), but EPOC32 and older versions of Symbian did rely on other means (setjmp/longjmp if I recall correctly). – otto Oct 10 '11 at 20:10
  • 1
    @OttoHarju: That's what I meant by "at least not directly". – Keith Thompson Oct 10 '11 at 20:12
3

I /never/ use exceptions. There are a number of reasons for this, but the two main reasons are that I have never needed them to produce robust code and that they reduce the performance at runtime.

I have worked on production code that is both using and disabling exceptions - the code that allowed exceptions was uniformly worse. In some places exceptions were used for genuine flow control rather than error handling, which is very heavyweight, anti-performance and difficult to debug. In general debugging problems in the exception filled code was more difficult than in the exception-free code - partly down to the stack and intrinsic difficulties of the exception mechanism, but much more than that it was because of the lazy code that was encouraged as a result of having exception handling available.

There is nothing seriously wrong with exceptions themselves /if you don't care about performance/ and don't have time to do something properly - they are a language feature for error handling and a good substitute for a proper error handling mechanism. However, there are almost always /better/ ways to handle errors - like with your own logic (its hard to elaborate on this - it is almost common sense). If its not your error, but comes from a library (e.g. the standard library) then you have to respect the choice of exceptions or have some crash, but I'd always question that choice. I have never seen a situation where exceptions were actually the best solution.

Assertions are more debuggable, error codes are less heavyweight... between the two, if used properly, you get easier to read, debug and maintain code which is faster. Its wins all round...

jheriko
  • 249
  • 1
  • 5
  • 1
    Nope. It's easier to misuse exceptions, but other than that exceptions work well. It's at least as easy to reason about, provided all your functions are exception-safe (and that's usually just a matter of using RTTI for all resources, which you should be doing anyway). Doing error codes properly can be extremely tedious, and can result in burying your program in a pile of error-handling code; in that case, exceptions are better. Remember, my doing things differently from you is not conclusive evidence that I don't care about doing things right. – David Thornley Oct 11 '11 at 22:00
  • ...as for why RTTI is bad that is a whole other story - the built-in RTTI in every compiler I have seen is trivially beatable - if you even need RTTI. Its all about context though - these things like RTTI and exceptions can be great for RAD and enterprise apps - they have no place in the world of high performance (e.g. games) computing. I've never seen a production game engine using either on any target where they could be turned off... – jheriko Nov 30 '11 at 16:03
  • 2
    Sorry - RAII is what I meant. If you're not using that, then not only exceptions are going to be messed up. (However, dynamic casts work very well in my work, and I do have to be concerned with performance.) – David Thornley Nov 30 '11 at 17:35
  • Interesting topic: I think exceptions allow a more concise error handling coding but error codes are more robust because they allow to handle errors locally (you can check the return code immediately in the caller while exception can bubble up the call-stack before they are caught and sometimes they are not caught, resulting in a crash. Unless you use catch (...)). – Giorgio Jun 03 '12 at 13:56
3

In the Joint Strike Fighter C++ coding standard by Bjarne et. al., exceptions are banned, due to the hard real-time requirements of fighter jets.

JSF++ is for hard-real time and safety-critical applications (flight control software). If a computation takes too long someone may die. For that reason, we have to guarantee response times, and we can't - with the current level of tool support - do that for exceptions. In that context, even free store allocation is banned! Actually, the JSF++ recommendations for error handling simulate the use of exceptions in anticipation of the day where we have the tools to do things right, i.e. using exceptions.

Quoted from Bjarne's C++ FAQ.

Remember, C++ probably runs the widest variety of software of all languages...

Macke
  • 2,576
  • 16
  • 16
  • JSF++ also bans use of "new" (other than placement new) and "delete". Which is one answer to the "how do you handle new failing without exceptions" bit of the question... – armb Aug 21 '13 at 13:57
  • @armb: Yes. See "In that context, even free store allocation is banned!" above. – Macke Aug 22 '13 at 05:28
2

It's kind of important in C++ library design. Often times with a C-interface it's kind of nasty to throw an exception out of your 3rd party library to the client. Point being that if your library throws, you're cutting out a set of clients who would have used it, given that it had a no-throw guarantee (for whatever reason that client has for a restriction on exceptions).

Personally I've seen exceptions abused when the team is told to "throw in an exception" whenever something not-so-terrible happens. Of course you see the error here- the exception was thrown in the code before anyone figured out what to do with it. That project had a few crashes as these deep-throws would rear out occasionally.

anon
  • 1,474
  • 8
  • 8
1

Perhaps in this regard, it's worth mentioning Embedded C++. Embedded C++ is a variant of C++ designed (obviously enough) for embedded systems. It's basically a proper subset of C++, with (among other things) templates, namespaces, and exception handling removed.

I should add that while EC++ made a bit of a splash when it was new, they seem to have mostly gone fairly quiet. I'm not sure if people have lost interest, or their first attempt was simply so perfect that nobody's seen any reason to mess with it for a decade or so. <closed captioning for the humor impaired>Yeah, right!</closed captioning>

Jerry Coffin
  • 44,385
  • 5
  • 89
  • 162
1

A good example is kernel mode programming.

You can use C++ there for cleaner code but without exceptions. There is no runtime library for them and exception handling use too much stack memory that is very limited in the kernel (I experimented with C++ exceptions in Windows NT kernel and exception throwing and unwinding eats a half of available stack - very easy to get stack overflow and crash the whole system).

Typically you define your own new and delete operators. Also I found pretty handy a placement new and c++11 rvalue references. No STL or other C++ user-mode libraries which rely on exceptions can be used.

Sergius
  • 111
  • 3
0

When you are trying to keep executable memory down. Typically done on embedded (or mobile) systems. For desktops apps its never needed however on servers it might be considered if you want as much ram as possible for the web server or for sql.