Google C++ style guide's No-exceptions rule; STL?

C++ExceptionStl

C++ Problem Overview


Google's C++ style guide says "We do not use exceptions". The style does not mention STL with respect to usage of exception. Since STL allocators can fail, how do they handle exceptions thrown by containers?

  1. If they use STL, how is the caller informed of allocation failures? STL methods like push_back() or map operator[] do not return any status codes.
  2. If they do not use STL, what container implementation do they use?

C++ Solutions


Solution 1 - C++

They say that they don't use exceptions, not that nobody should use them. If you look at the rationale they also write:

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

The usual legacy problem. :-(

Solution 2 - C++

We simply don't handle exceptions thrown by containers, at least in application-level code.

I've been an engineer at Google Search working in C++ since 2008. We do use STL containers often. I cannot personally recall a single major failure or bug that was ever traced back to something like vector::push_back() or map::operator[] failing, where we said "oh man, we have to rewrite this code because the allocation could fail" or "dang, if only we used exceptions, this could have been avoided." Does a process ever run out of memory? Yes, but this is usually a simple mistake (e.g., someone added a large new data file to the program and forgot to increase the RAM allocation) or a catastrophic failure where there's no good way to recover and proceed. Our system already manages and restarts jobs automatically to be robust to machines with faulty disks, cosmic rays, etc., and this is really no different.

So as far as I can tell, there is no problem here.

Solution 3 - C++

I'm pretty sure that they mean they do not use exceptions in their code. If you check out their cpplint script, it does check to ensure you are including the correct headers for STL containers (like vector, list, etc).

Solution 4 - C++

I have found that Google mentions this explicitly about STL and exceptions (emphasis is mine):

> Although you should not use exceptions in your own code, they are used > extensively in the ATL and some STLs, including the one that comes > with Visual C++. When using the ATL, you should define > _ATL_NO_EXCEPTIONS to disable exceptions. You should investigate whether > you can also disable exceptions in your STL, but if not, it is > OK to turn on exceptions in the compiler. (Note that this is only to > get the STL to compile. You should still not write exception handling > code yourself.)

I don't like such decisions (lucky that I am not working for Google), but they are quite clear about their behaviour and intentions.

Solution 5 - C++

You can’t handle allocation failures anyway on modern operating systems; as a performance optimization, they typically over-commit memory. For instance, if you call malloc() and ask for a really huge chunk of memory on Linux, it will succeed even if the memory required to back it actually isn’t there. It’s only when you access it that the kernel actually tries to allocate pages to back it, and at that point it’s too late to tell you that the allocation failed anyway.

So:

  1. Except in special cases, don’t worry about allocation failures. If the machine runs out of memory, that’s a catastrophic failure from which you can’t reliably recover.

  2. Nevertheless, it’s good practice to catch unhandled exceptions and log the e.what() output, then re-throw, since that may be more informative than a backtrace, and typical C++ library implementations don’t do that automatically for you.

  3. The whole huge thread above about how you can’t rely on crashing when you run out of memory is complete and utter rubbish. The C(++) standard may not guarantee it, but on modern systems crashing is the only thing you can rely on if you run out of memory. In particular, you can’t rely on getting a NULL or indeed any other indication from your allocator, up to and include a C++ exception.

  4. If you find yourself on an embedded system where page zero is accessible, I strongly suggest you fix that by mapping an inaccessible page at that location. Human beings cannot be relied upon to check for NULL pointers everywhere, but you can fix that by mapping a page once rather than trying to correct every possible (past, present and future) location at which someone might have missed a NULL.

I will qualify the above by saying that it’s possible you’re using some kind of custom allocator, or that you’re on a system that doesn’t over-commit (embedded systems without swap are one example of that, but not the only example). In that case, maybe you can handle out-of-memory conditions gracefully, on your system. But in general in the 21st century I’m afraid you are unlikely to get the chance; the first you’ll know that your system is out of memory is when things start crashing.

Solution 6 - C++

Stl itself is directly only throwing in case of memory allocation failure. But usually a real world application can fail for a variety of reasons, memory allocation failure just one of them. On 32 bit systems memory allocation failure is not something which should be ignored, as it can occur. So the entire discussion above that memory allocation failure is not going to happen is kind of pointless. Even assuming this, one would have to write ones code using two step initialization. And C++ exception handling predates 64 bit architectures by a long time. I'm not certain how far I should go in dignifying the negative professionalism shown here by google and only answer the question asked. I remember some paper from IBM in around 1997 stating how well some people at IBM understood & appreciated the implications of C++ Exception Handling. Ok professionalism is not necessary an indicator of success. So giving up exception handling is not only a problem if one uses STL. It is a problem if one uses C++ as such. It means giving up on

  • constructor failure
  • being able to use member objects and base class objects as arguments for any of the following base/member class constructors ( without any testing). It is no wonder that people used two step construction before C++ exception handling existed.
  • giving up on hierarchical & rich error messages in an environment which allows for code to be provided by customers or third parties and throw errors, which the original writer of the calling code could not possible have foreseen when writing the calling code and could have provided space for in his return error code range.
  • avoids such hacks as returning a pointer to a static memory object to message allocation failure which the authors of FlexLm did
  • being able to use a memory allocator returning addresses into a memory mapped sparse file. In this case allocation failure happens when one accesses the memory in question.(ok currently this works only on windows but apple forced the gnu team to provide the necessary functionality in the G++ compiler. Some more pressure from Linux g++ developer will be necessary to provide the this functionality also for them) (oops -- this even applies to STL)
  • being able to leave this C style coding behind us (ignoring return values) and having to use a debugger with debug executable to find out what is failing in a non trivial environment with child processes and shared libraries provided by third parties or doing remote execution
  • being able to return rich error information to the caller without just dumping everything to stderr

Solution 7 - C++

There is only one possibility to handle allocation failure under assumptions outlined in the question:

  • that allocator force application exit on allocation failure. In particular, this requires the cusror allocator.

Index-out-of-bound exceptions are less interesting in this context, because application can ensure they won't happen using pre-checks.

Solution 8 - C++

Late to the party here although I didn't see any comparisons between C++ exception handling at Google and exception handling in Go. Specifically, Go only has error handling via a built-in error type. The linked Golang blog post explicitly concludes

> Proper error handling is an essential requirement of good software. By employing the techniques described in this post you should be able to write more reliable and succinct Go code.

The creation of Golang certainly took considerations of best practices from working with C++ into account. The underlying intuition is that less can be more. I haven't worked at Google but do find their use of C++ and creation of Golang to be potentially suggestive of underlying best practices at the company.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAndreiView Question on Stackoverflow
Solution 1 - C++Bo PerssonView Answer on Stackoverflow
Solution 2 - C++hoffmanjView Answer on Stackoverflow
Solution 3 - C++Mark LoeserView Answer on Stackoverflow
Solution 4 - C++Yongwei WuView Answer on Stackoverflow
Solution 5 - C++al45tairView Answer on Stackoverflow
Solution 6 - C++user678269View Answer on Stackoverflow
Solution 7 - C++AndreiView Answer on Stackoverflow
Solution 8 - C++TylerView Answer on Stackoverflow