views:

395

answers:

5

What techniques can I use to avoid exceptions in C++, as mentioned in Google's style guide?

+1  A: 

The style guide says they "don't use exceptions" which is just that - they don't throw them and don't call anything that could throw them (for example, they would use the new(std::nothrow) instead of usual new because the latter will throw bad_alloc when it fails to allocate memory.

sharptooth
How do they manage to use libraries that throws exception?
yesraaj
They don't.
avakar
Or they don't use these library
Clement Herreman
They can wrap them and have and have a catch(...) around all the contents in every wrapper function.
Laserallan
+7  A: 
  1. Don't throw exceptions.
  2. Don't use STL (which relies heavily on exceptions).
  3. Use only new(std::nothrow) or override ::operator new to return 0 on failure.

Note that by avoiding exceptions, you're effectively throwing out lots of useful libraries, including Boost. Basically, you'll have to program everything from scratch.

avakar
I didn't realize the STL "relied heavily on exceptions", and indeed I remember that STL being incompatible with exceptions used to be a big problem. But I guess it does at least insofar as it has no other way to deal with allocation failures.
Kragen Javier Sitaker
It not just a question of allocation failures. Exceptions are the only way to indicate failure from constructors, notably from copy-constructors that are called on items during inserts.
avakar
Check out the EASTL, an STL without exceptions.
Edouard A.
@Edouard: Is the EASTL written by Google? :-)
rstevens
I don't think you're allowed to override `operator new` to fail in that way. You certainly shouldn't. It would force correct code to check for NULL pointers even when they're intentionally using the throwing `new`.
MSalters
avakar: When would it be a good idea to store an object in an STL container whose copy-constructor could fail for some reason other than a memory allocation failure? It seems like the common cases (acquiring some other resource like a file descriptor or lock, or invalid constructor arguments) are excluded from this condition. You sure don’t want the STL copying your RAII lock objects behind your back!
Kragen Javier Sitaker
The EASTL sure is interesting. Too bad it's not possible to get it.
Dan Hook
Kragen, STL containers are allowed to copy the contained objects as they see fit. The copy-construction can, however, fail at any time. Operations on containers generally have strong exception guarantees: http://en.wikipedia.org/wiki/Exception_guarantees.
avakar
@Edouard And how exactly is he supposed to check out a closed source library that is not even licensed?
Frank Krueger
A: 

In some compilers, you may be able to turn off exception handling. This could cause unexpected results with external code though - it is not something I would want to try.

Other than that, the obvious first step would be to avoid throwing exceptions from your own code, probably with liberal use of the nothrow directive, and attempt to avoid throwing exceptions from external (3rd party) code through defensive programming.

That means that your code needs to be aware of possible external exceptional failure conditions all the time, such as running out of memory, out of disk space, loss of an internet connection, hardware failure, and any number of other circumstances that might cause code to throw...

In some cases you may be able to use exception-free versions of some code (such as throwing-new vs. non-throwing new).

MadKeithV
+2  A: 

Not throwing exceptions in your own code is relatively easy: you just don't use the throw statement.

Not throwing exceptions from memory allocation failures is a little more painful: either you don't use normal new (use new(std::nothrow) or malloc or something instead), or you use some nonstandard compiler option to get it to do something nonstandard when it fails (e.g. immediately terminate your program, or return 0), or you override operator new to do something nonstandard when it fails.

If your chosen approach is to immediately terminate the program, you can implement this with set_new_handler(), which I had forgotten about until litb reminded me.

That leaves the problem of dealing with exceptions generated by C++ libraries you don't maintain. Generally you'll have to wrap library calls in a wrapper that looks something like this:

int DoSomething(int &output, const int input) throw() {
  try {
    output = library_do_something(input);
    return 1;
  } catch (...) {
    return 0;
  }
}

The catch (...) catches all possible C++ exceptions from library_do_something (as well as the assignment operator on output, which isn't relevant here), throws away all the information they may have contained, and then maps all those failures to 0.

Note that this style means that you can't use RAII at all, not even a little bit, because you have no way of signaling failure within a constructor. The whole point of RAII is that you acquire all your resources inside of constructors so that they will be properly released by a destructor during exception propagation. But resource acquisition is something that can essentially always fail. So you can't do that inside a constructor.

Kragen Javier Sitaker
You can install a new handler. Operator new will call it when it doesn't have memory available, and from that handler, you can either manage to get memory or terminate the program.
Johannes Schaub - litb
I had forgotten about `set_new_handler()`, thanks, litb! I'm updating my answer.
Kragen Javier Sitaker
Just do `kill(0,9)` instead of throwing an exception. OK, you'll also be kissing your whole process group goodbye, but that pesky exception won't be disturbing your beautiful code! ;-)
Donal Fellows
+2  A: 

I'm interested to know why one would want to avoid exceptions in C++ and what mechanism one would replace them with to deal with the reality of unexpected failure while still maintaining decent structure.

Sure adding them to a existing codebase that doesn't use RAII type semantics is extremely costly - but if one is doing green field development then what alternative would you suggest and how are going to justify not using high quality libraries that do use exceptions vs. writing your own exception free / bug free alternatives?

Tom Kirby-Green
In addition to the performance and space problems of exceptions, which empirically exist even though people deny them, some platforms simply don't support exceptions in a trustworthy way. Some embedded machines' C++ compilers, for example, just don't have working exceptions.
Crashworks
Personally I don't like using exceptions in C++, because it makes it extremely difficult to predict the control flow of the program. Since any C++ function can throw any exception without declaring it, using exceptions means that you can't predict what *any* function will do unless you grovel over the *entire* call tree beneath it. That means that verifying the behavior of a function wrt exceptions is a problem with geometrically expanding cost for the programmer. Java, OTOH, gets it right--Java methods declare the exceptions they can throw, and the declarations are enforced at compile time.
Jeremy Friesner