17

The supposed ethos of C++ is "what you use, you pay for". However, this can be quite debilitating due to exceptions and their pervasive use in the STL.

Before anybody says "just turn exceptions on", life is not so generous with the programming environments we must live in. Mine is kernel programming where the execution environment does not provide enough C++ runtime to unwind the stack, etc.

STL containers will throw allocation failure exceptions when they cannot reallocate storage for their underlying backing stores. When exceptions are not enabled in the environment, the program will crash rather mysteriously: I have seen implementations straight-up abort or just assume that the allocation worked even if it did not.

Many C ADT libraries that I have come across deal with this problem upfront by returning an error code or having the error as an output parameter.

What is the "best" C++ way of dealing with this problem?

To clarify

I do not want to use the standard library, I cannot. I am not asking "how do I do that which cannot be done". I am asking: "given a clean slate, how should the container library be built."

user1290696
  • 489
  • 1
  • 4
  • 10
  • You could look at existing implementations and either manually remove all use of exceptions or rewrite the containers to use success/error codes. The best strategy for tackling the lack of STL would be to assess which containers you actually need and implement them as you need them. – Pharap May 28 '14 at 08:40

2 Answers2

19

That's easy: stop believing you should use the standard library for everything.

The standard library is intended to be the default place you go for functionality. However, that doesn't mean it is appropriate in every situation. Such as kernel programming, for example. This is a fairly niche environment, where you need direct and explicit control over things that the majority of C++ programmers don't care about.

The C++ standard mechanism for signaling failure, particularly of something like internal memory allocation from a container, is to throw an exception. The vast majority of applications will not bother to catch that exception; in the unlikely event that they are out of memory, they just die. Which is fine for them. Returning an error code in these cases is, at best difficult (consider reallocation of a std::vector<std::string>. What happens if one of the inner std::strings is what gets OOM? Who gets the error code? How would you even signal the failure of a constructor, since the exception is thrown by std::strings copy constructor?). And only people who really need to care will care enough to catch it.

You're working in a restricted environment, an environment that the standard library is not designed to handle. So... don't use it in that environment.

My suggesting is to track down a copy of EASTL. It's really designed for this sort of thing. The Github repo I linked you to has some bug fixes and so forth, but it's still mostly the same. It's not a bad bit of code. Their STL-like containers provide most of the interface, so they can be mostly drop-in replacements. But they provide special functionality to specifically control memory allocations. And they don't throw (or at least, you can turn off throwing).

cylus
  • 357
  • 1
  • 4
  • 14
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 2
    Or at least, write your own containers. `sort`, `partition`, `transform`, etc. and friends are still just fine. – Billy ONeal Mar 25 '12 at 04:36
  • I have updated my question to be a little bit more clear as to which problem I am actually trying to solve. – user1290696 Mar 25 '12 at 04:41
  • EASTL, unfortunately, is GPL'd code. This is inappropriate for the projects that I work on. – user1290696 Mar 25 '12 at 04:43
  • 1
    @user1290696: That's a completely different question now. It's now an advice question, which is not answerable, since everyone has their ideas for how to do it and none of them are right or wrong. – Nicol Bolas Mar 25 '12 at 04:45
  • @NicolBolas I figured that library design in an exception-free environment has been a "solved" problem that others have encountered. Furthermore, a question having more than one answer is pretty much the opposite of being unanswerable... – user1290696 Mar 25 '12 at 04:51
  • 1
    @user1290696: It appears to be the BSD license, not GPL. – Benjamin Lindley Mar 25 '12 at 05:58
  • 1
    @user1290696: "Furthermore, a question having more than one answer is pretty much the opposite of being unanswerable..." That's not how it works. [See here for a bit more detail](http://meta.stackexchange.com/a/28561/164572), but the real info comes from the blogs. Subjective questions are not what SO is for, and speculation on design (how best to design X) is ultimately subjective. – Nicol Bolas Mar 25 '12 at 06:03
3

It seems the problem is really your environment. Stack unwinding is not terribly complicated. I can see why you'd want to put some restrictions on it - throwing a 10 MB object is legal C++ - but even in kernel mode you should be able to support throwing std::bad_alloc through non-virtual calls.

With that in mind, the STL design is perfectly sane. The interface requires only minimal exception support, and the implementation can be tailored to the environment.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • Same problem here, I'm working on a STM32 with 132kb flash. So there is no way to turn on exceptions and I need some replacement for things like std::vector, or write it myself. – Tarion Jan 10 '18 at 14:02