“We do not use C++ exceptions” — What's the alternative? Let it crash?

前端 未结 7 435
南旧
南旧 2021-02-01 14:25

\"We do not use C++ exceptions.\"

If you don\'t use exceptions, what happens when there\'s an error? You just let the program crash?

相关标签:
7条回答
  • 2021-02-01 14:47

    Or you could read a little further:

    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 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.

    0 讨论(0)
  • 2021-02-01 14:49

    If you're writing code and reach a point where you've identified an issue for which you would typically throw an exception, but wish to abide by some stipulation that exceptions won't be used, then you have to find another way to let the client code know of the error.

    As many existing answers document, you could return a sentinel value (e.g. a true/false success value, an enum). This practice is widely familiar from common C functions specified by POSIX and libc, like fopen(), strstr() or printf().

    Another important option is to set some internal state that they can query later. Why might you want or need to do the latter? Because some functions, crucially C++ constructors and operators, don't typically give you the opportunity to return an error code. For example, in:

      X x1(something), x2(whatever);
      fn(x1 + x2);
    

    X::X(...) can't return anything. X::operator+ may be invoked (assuming + isn't invoked on results of conversion operators), but fn() is presumably expecting a const X& (or X&& with C++11), and operator+ needs to return an X so it works in the successful situation. You have no chance to return a distinct type of error code. class X may need to set some internal state that other code (perhaps fn(), perhaps a statement after fn() is called) tests to take appropriate action.

    So, you end up with something like:

    X x1(something), x2(whatever);
    assert(x1.is_valid() and x2.is_valid());
    X x3 = x1 + x2;
    assert(x3.is_valid());
    fn(x3);
    

    Note that this error handling convention is verbose and prone to being overlooked or ignored by client coders - one of the reasons exceptions were created. An interesting variation on this is utilised by most float point hardware - certain operations like division by 0 or under/overflows may set the register to sentinel values such as Not a Number "NaN" or +/- Infinity, and then operations involving an argument in such a state propagate the state to their result. For example, x = 8 + y / 0; z = x + 2; will set z to a sentinel too. The idea here is that you can write code that calculates the correct result whenever possible, and check once before using the result to see if an error from anywhere in the calculation code invalidated that result. It works ok for maths code sometimes, particularly when you're not making branching decisions based on the current values of the variables, but unfortunately in many situations you either won't be able or won't want to make all the users of a potentially invalid object code super-defensively to handle and propagate error states.

    Using C++ without exceptions serious compromises the usability, maintainability, concision and elegance of the language.

    As an alternative to a total ban on exception usage, in some environments you may be able to catch all exceptions at the boundaries of your API, then return error codes or sentinel values in a "C" style. This allows better coding internally, but better interoperability externally. Sadly, sometimes any use of exceptions is impractical, as your code will execute in an environment where the exception-handling mechanisms aren't provided... perhaps inside a kernel, driver, or embedded environment with a stripped down C++-style compiler. Such an environment is not true C++ though, as it's not Standard compliant.

    0 讨论(0)
  • 2021-02-01 14:50

    The linked style guide explains it well:

    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.

    It is relatively easy in C++ to create robust code without using exceptions or worrying about Exception Guarantees. With return codes and asserts, exceptions are really limited to programmer errors.

    0 讨论(0)
  • 2021-02-01 14:57

    No, the alternative is to do what people have done for ages in C... you return an error status code that indicates whether the function succeeded or not, and depending on the ways in which it can fail, you might have one or more out parameteters in which you indicate the way in which it failed (or you incorporate the type of failure in the error status code, again it's a case-by-case thing).

    0 讨论(0)
  • 2021-02-01 15:06

    Alternatives to exceptions other than return codes:

    • LISP-style conditional handler.
    • Software signals and slots, QT-style.
    • Hardware interrupt or signal handler without a stack unwind. It's the stack unwind that is the problem with exceptions on embedded devices.
    • longjmp / setjmp
    • Callback function
    • Flag value e.g. errorno (Unix), GetLastError (Windows), glGetError (OpenGL), etc.
    • Message queue, if program is event driven
    • Mutable functor. Handler object as input-output parameter, pointer is changed on error.
    • Fibers or threads with an error resolution co-routine
    • asm __int 3 or CPU-equivalent
    • Overlay instructions or trampoline functions.

    ...and many more. Many of the above-listed are embedded device friendly.

    0 讨论(0)
  • 2021-02-01 15:08

    You use the error-code-returning versions of functions and act according to the return value.

    0 讨论(0)
提交回复
热议问题