What does it take to write memory safe C++ applications? - c++

Is it possible to either create a coding standard or use of a library that can be proved to eliminate any memory management errors in C++?
I'm thinking of something like Java, it is just impossible to for example have dangling pointers in Java applications.

Is it possible to either create a coding standard or use of a library that can be proved to eliminate any memory management errors in C++?
Yes and no.
Even if you use a very strict standard, doing so will limit you to a very narrow subset of the C++ language. For example, the Power of Ten (Rules for Developing Safety-Critical Code) says that you should disable heap usage entirely. However that alone doesn't stop you from creating memory corruption.
I think if there were an exact answer to this question, the industry would've solved this decades ago, but here we are...
I don't believe that there is a definite way to make sure your code is totally safe, but there are best practices which will help you make sure there are as few problems as possible.
Here are some suggestions:
As mentioned earlier, disallowing heap usage entirely might help you get rid of all the memory management problems, but it doesn't solve the problem completely because it doesn't save you from eg. stray pointer writes.
I recommend you read the about The Rule of Three, Five and Zero which explain some of the stuff you need to take care of.
Instead of managing memory on your own, use smart pointers like shared_ptr, unique_ptr etc. But course, you could still abuse these if you wanted to. (For example shared_ptr will not help you if you have circular references...)
Use memory checker tools like valgrind, which can help you discover problems and verify that your code is error-free.
Even if you keep to any coding standard or best practice, errors can and will happen. Nobody guarantees that you will be safe. However, by keeping to these suggestions you can minimize the chance and impact of errors.

Is it possible to either create a coding standard or use of a library
that can be proved to eliminate any memory management errors in C++?
No.
But the same is true for Java. While Java does not technically allow memory leaks, it does have them (and other resource leaks) in practice if you do not pay attention.
A classical example, known particularly well in the Android world, is when a collection of listener instances keeps growing the longer a program runs, because listeners forget to unregister themselves. This can quickly cause hundreds of MBs leaking in a GUI application when the listener is an instance of some window or view class that keeps itself references to big graphics. Since all of that memory is still reachable, garbage collection cannot clean it up.
The fact that you have not technically lost the pointer (it's still in the collection) does not help you at all. Quite the contrary; it's the cause of the leak because it prevents garbage collection.
In the same vein as above, while Java does not technically allow dangling pointers, similar bugs can cause you to access a pointer to some window or view object which is still in a valid memory area for your program but which should no longer exist and is no longer visible. While the pointer access itself does not cause any crash or problem, other kinds of errors or crashes (like a NullPointerException) usually follow soon enough because the program logic is messed up.
So much for the bad news.
The good news is that both languages allow you to reduce memory-management problems if you follow simple guidelines. As far as C++ is concerned, this means:
Use standard collections (like std::vector or std::set) whenever you can.
Make dynamic allocation your second choice. The first choice should always be to create a local object.
If you must use dynamic allocation, use std::unique_ptr.
If all else fails, consider std::shared_ptr.
Use a bare new only if you implement some low-level container class because the existing standard container classes (likestd::vector or std::set) do not work for your use case. This should be an extremely rare case, though.
There is also the Boehm garbage collector for C++, but I've never used it personally.

Related

Dynamic allocation and large data structures in C++

Lately, I learned there is a consensus among C++ programmers that the new, delete and delete[] operators should be avoided as often as possible, as already discussed here, here or here. While searching, I even stumbled upon an April Fools' joke stating that these operators would become deprecated in C++20.
I happen to write and maintain a C/C++ program, written in such language in order to carry on useful libraries and classes written by other programmers. As it must run in quite limited environments (i.e., old Linux distributions with the bare minimum in terms of programs), I can't rely on features brought C++11 and later versions (such as smart pointers), and I sticked so far to a mix of C and Java programming habits while expanding my program. Among others, I used quite often dynamic allocation with new and delete - which sounds, of course, to be a problem.
To ease the maintenance of my code by future programmer(s), I would like to minimize dynamic allocation with said keywords in my code. The problem is that my program has to manage some quite large data structures used for (almost) the entire execution. As a consequence, I struggle to figure out why I should avoid dynamic allocation in these situations.
To simplify, consider I have a data structure (modeled as an object) worth 10 Megaoctets which is used for the entire execution of the program and which the size in memory can increase over time. My questions are the following:
Is dynamic allocation of the object with new still a bad practice in this particular context ? What are the better alternatives ?
Suppose now I instantiate somewhere in my program a new object without using new, do some operations on it which could slightly change its size, then use a method to insert it in my data structure. How does it work, memory-wise, if automatic allocation (as mentioned here) is used ?
Many thanks in advance.
You could try using boost smart pointers.
https://www.boost.org/doc/libs/1_71_0/libs/smart_ptr/doc/html/smart_ptr.html
They are very similar to the C++ 11 smart pointers, but available as a library which should work in pre C++ 11 environments. If you decide to go this way, you may also want to look at this
How to include only BOOST smart pointer codes into a project?
Now, I'm wondering if you are confusing the new/delete functions with dynamic allocation in general. Smart Pointers are still dynamic allocation, however they are able to clean themselves up so that you don't have to remember too. That's why they are preferred over using new/delete (malloc/free, etc), they are much less likely to lead to memory leaks.
Automatic allocation is fine when the object lifespan allows it, but if you need the object to persist outside of the function it was declared in, you'll need dynamically allocated memory.
Is dynamic allocation of the object with new still a bad practice in this particular context?
Yes, it's bad to have a new in your code mainly because of memory leaks if delete or delete[] isn't called, especially in the face of exceptions.
What are the better alternatives?
Write smart pointers and have them either call new themselves or be called with a new expression:
myUniquePtr<myObj> obj_ptr(new myObj);
and then use RAII to have their destructors call delete or delete[].
Make your smart pointer behave as naked pointer in every other way (overload operator-> etc). Then it'll work in your code with the same syntax as your raw pointers did without having to worry about whether a heap object is deleted at the end of a it's life-cycle no matter what paths the code can take.

Why can't C++ have an optional transparent garbage collector

There's a related question but this one is slightly different and I'm not happy with any of the answers to the related question :)
I'm going to ask this question in the negative by asserting it is not possible to have an optional transparent garbage collector for C++ and hoping someone will prove me wrong. Yes, Stroustrup tried this on and has repeatedly failed not because of technical issues but because of conformance issues. Performance is not an issue here.
The reason C++ will never have such a collector is that being optional a program which runs without the collector must implement all the required memory management manually. Adding a collector may then provide some performance benefits, but it isn't clear they're worthwhile (yes, a collector can be faster).
What you cannot obtain is automatic memory management, which is the principal reason for desiring a collector. You would get this with mandatory collection (without necessarily sacrificing RAII or other things if you choose to do correct manual management). A mandatory collector with optional manual memory management is tenable.
Unfortunately, the only way to get a mandatory collector creates an incompatibility with earlier versions of C++ not using a collector: in other words we have to define a new language if we want automatic transparent memory management.
So my contention is: C++ will never have garbage collection because it is locked into a historical development which requires upward compatibility: mandatory collection with optional manual memory management is viable but transparent optional garbage collection is not.
Prove me wrong by exhibiting a tenable optional transparent garbage collection model!
EDIT:
Oooo .. I think I have the answer. Can someone quote the Standard where it requires programs to delete heap allocated objects?
Because: that clause, if it exists, is the only thing stopping optional transparent garbage collection. There may even be enough time to get that clause removed from C++1x.
Without such a clause, a program can leak memory without the behaviour being undefined: the behaviour when out of memory is just the same as it usually is. And so tacking on a garbage collector will do nothing to the specified semantics: they're well defined or not, independently of whether the collector is used or not.
Prove me wrong by exhibiting a tenable optional transparent garbage collection model!
See: C++/CLI.
The difficulty with putting a garbage collector with existing C++ code is that C++ often relies on deterministic object destruction in order to make things happen; as is done in RAII. Sure, the garbage collector would be able to make most kinds of memory RAII transparent, but plenty of RAII related concepts don't have anything to do with memory. For example, sockets, streams, and locks all are amenable to some form of RAII management, and none of these would work well if deterministic destruction was not preserved.
Therefore, it probably won't be "transparent" -- it'd have to be something like C++/CLI where you have to say "I want this to be garbage collected" -- but it's by all means reasonable and possible.
This may be better suited as a comment rather than an answer, and may draw many downvotes. So be it.
Whenever someone asks a question like "Why can't C++ have GC?" I think to myself "because I don't want your damned garbage collection. I want to control when objects live. I want to control when objects die. I want destruction and deallocation to be deterministic, not based on some hokus pokus black magic. I don't need GC to write better programs. Therefore, GC will do nothing for me but get in my way."
But even beyond that, consider this. C# and the other .NET languages have GC built in. The compilers and the CLR for these languages were written primarily in C++. This includes the memory management facilities, except for a few performance-critical pieces written in assembler.
So you might say that anything that C# can do, C++ can do, since C++ begat C#.
Go ahead, downvote away...
"Why doesn't my Lamborghini have a snow plow blade mount?" Because it's not designed for snow removal ;)
C++ wasn't designed like C# and has different uses. Use the right tool for the right job and life is much easier.
Can I prove you wrong by giving examples of optional transparent garbage collectors for C++?
boehmgc
libgc
There's also a good discussion on the Boehm site that should be required reading for questions like this.
I think that you're taking the wrong approach. There's no reason that a GC should be transparent- why not have a std::gc_pointer<T>?
You need to consider the genuine purpose of a GC. This isn't to solve memory management, because the existing smart pointers (in C++0x) solve this just fine - it's to offer a different performance characteristic to manual memory management, that's very suitable for temporary allocations. Why not just have a std::gc_new? We already have a std::make_shared.
And, in C++0x, it is already implementation defined whether or not undeleted objects are deleted automatically.
The real problem is not so much ensuring object destruction happens deterministically (that could probably be done without too much trouble: when an object goes out of scope (or delete is called in the case of heap-allocated objects), its destructor can be called, while the actual reclaiming of memory can be left until a later garbage collection) -- but rather how to identify what to collect.
To do that, the GC needs to be able to traverse the object graph.
In "properly" GC'ed languages, that's simple enough, as every object is tagged with a type pointer of some kind, allowing the GC to know the structure of the object it is visiting.
In C++, there is usually no such thing. There is no way for the GC to know whether the word it is looking at is a pointer or not, and equally important, whether or not the next word is part of the same structure/array, or if it is unallocated.
Of course, the standard doesn't prohibit an implementation from adding such type information, but that would carry a cost in runtime performance and memory usage, which is incompatible with C++'s "you only pay for what you use" philosophy.
An alternative option, taken by the GC's that exist, is to implement a conservative GC, which might not reclaim all memory, because it has to guess at whether a word is a pointer or not, and when in doubt, it has to be pessimistic.

Most common reasons for unstable bugs in C++?

I am currently working on a large project, and I spend most of the time debugging. While debugging is a normal process, there are bugs, that are unstable, and these bugs are the greatest pain for the developer. The program does not work, well, sometimes... Sometimes it does, and there is nothing you can do about it.
What can be done about these bugs? Most common debugging tools (interactive debuggers, watches, log messages) may lead you nowhere, because the bug will disappear ... just to appear once again, later. That is why I am asking for some heuristics: what are the most common reasons for such bugs? What suspicious code should we investigate to locate such a bugs?
Let me start the list:
using uninitialized variables.
Common misprints like mMember =
mMember;
thread synchronization.
Sometimes it can be a matter of
luck;
working with non-smart
pointers, dereferencing invalid
ones;
what else?
IME the underlying problem in many projects is that developers use low-level features of C++ like manual memory management, C-style string handling, etc. even though they are very rarely ever necessary (and then only well encapsulated in classes). This leads to memory corruption, invalid pointers, buffer overflows, resource leaks and whatnot. All the while nice and clean high-level constructs are available.
I was part of the team for a large (several MLoC) application for several years and the number of crashing bugs for different parts of the application nicely correlated to the programming style used within these parts. When asked why they wouldn't change their programming style some of the culprits answered that their style in general yields more performance. (Not only is this wrong, it's also a fact that customers rather have a more stable but slower program than a fast one that keeps crashing on them. Also, most of their code wasn't even required to be fast...)
As for multi-threading: I don't feel expert enough to offer solutions here, but I think Herb Sutter's Effective Concurrency columns are a very worthwhile read on the subject.
Edit to address the discussions in the comments:
I did not write that "C-style string handling is not more performant". (Certainly a lot of negation in this sentence, but since I feel misread, I try to be precise.) What I said is that high level constructs are not in general less performant: std::vector isn't in general slower than manually doing dynamically allocated C arrays, since it is a dynamically allocated C array. Of course, there are cases where something coded according to special requirements will perform better than any general solution -- but that doesn't necessarily mean you'll have to resort to manual memory management. This is why I wrote that, if such things are necessary, then only well-encapsulated in classes.
But what's even more important: in most code the difference doesn't matter. Whether a button depresses 0.01secs after someone clicked it or 0.05secs simply doesn't matter, so even a factor 5 speed gain is irrelevant in the button's code. Whether the code crashes, however, always matters.
To sum up my argument: First make it work correctly. This is best done using well-proven off-the-shelf building blocks. Then measure. Then improve performance where it matters, using well-proven off-the-shelf idioms.
I was actually going to post a question that asked exactly the opposite - do others find, as I do, that you spend almost no time using the debugger when working with C++? I honestly cannot remember the last time I used one - it must have been about six months ago.
Frankly, if you spend most of the time in the debugger, I think there is something very wrong with your basic coding practices.
Race conditions.
These are one of the few things that still sends a shiver down my spine when it comes up in debugging (or in the issue tracker). Inherently horrible to debug, and extremely easy to create. The three most common causes of bugs in my C++ software have been race conditions, reliance on uninitialised memory, and reliance on static constructor order.
And if you don't know what race conditions are, chances are they're the cause of your instability ;)
If you are really in a position where you already have bad code that breaks, the best plan is probably to throw as many tools at it as you can (OS/lib-level memory checking, automated testing, logging, core dumps, etc) to find the problem areas. Then rewrite the code to do something more deterministic. Most of the bugs come from people doing things that mostly work most of the time, but C++ offers stronger guarantees if you use the right tools and approaches.
Haven't seen this one mentioned yet:
Inheriting from a class that does not have a virtual destructor.
Reading from uncached memory while a cache line is being written back over the memory (This is a right bastard to find).
Buffer overwrites
Stack overflows!
The only 3 i can think of at the mo ... may edit later :)
buffer overflows
using pointers to deleted objects
returning invalid references or references to out of scope objects
unhandled exceptions
resource leaks (not only memory)
infinite recursion
dynamic libraries version mismatch
Not really a C++ issue but seen in a C/C++ project.
The trickiest issue I had to deal with was an initialization issue when starting up the OS on our platform that lead to unusual crashes. It took years before we found out what happened. Before that we ran the system overnight and if it didn't crash, then it was normally okay.
Luckily, the OS isn't sold anymore.
addresses and memory used before allocation or after deallocation, segmentation faults, arrayoutofbounds, offset, threadlocks, unintelligible operator overloading, inline assembly, void exit and void in general where return values are desired complicates where math.h functions are worth a look since all math.h functions both have working arguments and return values compared to other library overly void, emptiness tests, nils, nulls and voids. 4 general conventions I recommend are return values, arguments, ternary choices and invertible changes. Faultprone to avoid are vectors (use arrays instead) void with empty arguments and in my subjective opinion I avoid the switch statement in favor of more intelligible or readable if...elseif or more abstract "is".
C++ also has rather lousy forward compatibility compared to scripts and interpreted, to try a decade old Java it still runs unchanged and safe in later vm.

Embedded C++ : to use STL or not?

I have always been an embedded software engineer, but usually at Layer 3 or 2 of the OSI stack. I am not really a hardware guy. I have generally always done telecoms products, usually hand/cell-phones, which generally means something like an ARM 7 processor.
Now I find myself in a more generic embedded world, in a small start-up, where I might move to "not so powerful" processors (there's the subjective bit) - I cannot predict which.
I have read quite a bit about debate about using STL in C++ in embedded systems and there is no clear cut answer. There are some small worries about portability, and a few about code size or run-time, but I have two major concerns:
1 - exception handling; I am still not sure whether to use it (see Embedded C++ : to use exceptions or not?)
2 - I strongly dislike dynamic memory allocation in embedded systems, because of the problems it can introduce. I generally have a buffer pool which is statically allocated at compile time and which serves up only fixed size buffers (if no buffers, system reset). The STL, of course, does a lot of dynamic allocation.
Now I have to make the decision whether to use or forego the STL - for the whole company, for ever (it's going into some very core s/w).
Which way do I jump? Super-safe & lose much of what constitutes C++ (imo, it's more than just the language definition) and maybe run into problems later or have to add lots of exception handling & maybe some other code now?
I am tempted to just go with Boost, but 1) I am not sure if it will port to every embedded processor I might want to use and 2) on their website, they say that they doesn't guarantee/recommend certain parts of it for embedded systems (especially FSMs, which seems weird). If I go for Boost & we find a problem later ....
I work on real-time embedded systems every day. Of course, my definition of embedded system may be different than yours. But we make full use of the STL and exceptions and do not experience any unmanageable problems. We also make use of dynamic memory (at a very high rate; allocating lots of packets per second, etc.) and have not yet needed to resort to any custom allocators or memory pools. We have even used C++ in interrupt handlers. We don't use boost, but only because a certain government agency won't let us.
It is our experience you can indeed use many modern C++ features in an embedded environment as long as you use your head and conduct your own benchmarks. I highly recommend you make use of Scott Meyer's Effective C++ 3rd edition as well as Sutter and Alexandrescu's C++ Coding Standards to assist you in using C++ with a sane programming style.
Edit: After getting an upvote on this 2 years later, let me post an update. We are much farther along in our development and we have finally hit spots in our code where the standard library containers are too slow under high performance conditions. Here we did in fact resort to custom algorithms, memory pools, and simplified containers. That is the beauty of C++ though, you can use the standard library and get all the good things it provides for 90% of your use cases. You don't throw it all out when you meet problems, you just hand-optimize the trouble spots.
Super-safe & lose much of what
constitutes C++ (imo, it's more than
just the language definition) and
maybe run into problems later or have
to add lots of exception handling &
maybe some other code now?
We have a similar debate in the game world and people come down on both sides. Regarding the quoted part, why would you be concerned about losing "much of what constitutes C++"? If it's not pragmatic, don't use it. It shouldn't matter if it's "C++" or not.
Run some tests. Can you get around STL's memory management in ways that satisfy you? If so, was it worth the effort? A lot of problems STL and boost are designed to solve just plain don't come up if you design to avoid haphazard dynamic memory allocation... does STL solve a specific problem you face?
Lots of people have tackled STL in tight environments and been happy with it. Lots of people just avoid it. Some people propose entirely new standards. I don't think there's one right answer.
The other posts have addressed the important issues of dynamic memory allocation, exceptions and possible code bloat. I just want to add: Don't forget about <algorithm>! Regardless of whether you use STL vectors or plain C arrays and pointers, you can still use sort(), binary_search(), random_shuffle(), the functions for building and managing heaps, etc. These routines will almost certainly be faster and less buggy than versions you build yourself.
Example: unless you think about it carefully, a shuffle algorithm you build yourself is likely to produce skewed distributions; random_shuffle() won't.
Paul Pedriana from Electronic Arts wrote in 2007 a lengthy treatise on why the STL was inappropriate for embedded console development and why they had to write their own. It's a detailed article, but the most important reasons were:
STL allocators are slow, bloated,
and inefficient
Compilers aren't actually very good at inlining all those deep function calls
STL allocators don't support explicit alignment
The STL algorithms that come with GCC and MSVC's STL aren't very performant, because they're very platform-agnostic and thus miss a lot of microoptimizations that can make a big difference.
Some years ago, our company made the decision not to use the STL at all, instead implementing our own system of containers that are maximally performant, easier to debug, and more conservative of memory. It was a lot of work but it has repaid itself many times over. But ours is a space in which products compete on how much they can cram into 16.6ms with a given CPU and memory size.
As to exceptions: they are slow on consoles, and anyone who tells you otherwise hasn't tried timing them. Simply compiling with them enabled will slow down the entire program because of the necessary prolog/epilog code -- measure it yourself if you don't believe me. It's even worse on in-order CPUs than it is on the x86. For this reason, the compiler we use doesn't even support C++ exceptions.
The performance gain isn't so much from avoiding the cost of an exception throw — it's from disabling exceptions entirely.
Let me start out by saying I haven't done embedded work for a few years, and never in C++, so my advice is worth every penny you're paying for it...
The templates utilized by STL are never going to generate code you wouldn't need to generate yourself, so I wouldn't worry about code bloat.
The STL doesn't throw exceptions on its own, so that shouldn't be a concern. If your classes don't throw, you should be safe. Divide your object initialization into two parts, let the constructor create a bare bones object and then do any initialization that could fail in a member function that returns an error code.
I think all of the container classes will let you define your own allocation function, so if you want to allocate from a pool you can make it happen.
The open source project "Embedded Template Library (ETL)" targets the usual problems with the STL used in Embedded Applications by providing/implementing a library:
deterministic behaviour
"Create a set of containers where the size or maximum size is determined at compile time. These containers should be largely equivalent to those supplied in the STL, with a compatible API."
no dynamic memory allocation
no RTTI required
little use of virtual functions (only when absolutely necessary)
set of fixed capacity containers
cache friendly storage of containers as continously allocated memory block
reduced container code size
typesafe smart enumerations
CRC calculations
checksums & hash functions
variants = sort of type safe unions
Choice of asserts, exceptions, error handler or no checks on errors
heavily unit tested
well documented source code
and other features...
You can also consider a commercial C++ STL for Embedded Developers provided by E.S.R. Labs.
for memory management, you can implement your own allocator, which request memory from the pool. And all STL container have a template for the allocator.
for exception, STL doesn't throw many exceptions, in generally, the most common are: out of memory, in your case, the system should reset, so you can do reset in the allocator. others are such as out of range, you can avoid it by the user.
so, i think you can use STL in embedded system :)
In addition to all comments, I would propose you reading of Technical Report on C++ Performance which specifically addresses topics that you are interested in: using C++ in embedded (including hard real-time systems); how exception-handling usually implemented and which overhead it has; free store allocation's overhead.
The report is really good as is debunks many popular tails about C++ performance.
It basically depends on your compiler and in the amount of memory you have. If you have more than a few Kb of ram, having dynamic memory allocation helps a lot. If the implementation of malloc from the standard library that you have is not tuned to your memory size you can write your own, or there are nice examples around such as mm_malloc from Ralph Hempel that you can use to write your new and delete operators on top.
I don't agree with those that repeat the meme that exceptions and stl containers are too slow, or too bloated etc. Of course it adds a little more code than a simple C's malloc, but judicious use of exceptions can make code much clear and avoid too much error checking blurb in C.
One has to keep in mind that STL allocators will increase their allocations in powers of two, which means sometimes it will do some reallocations until it reaches the correct size, which you can prevent with reserve so it becomes as cheap as one malloc of the desired size if you know the size to allocate anyway.
If you have a big buffer in a vector for example, at some point it might do a reallocation and ends using up 1.5x the memory size that you are intending it to use at some point while reallocating and moving data. (For example, at some point it has N bytes allocated, you add data via append or an insertion iterator and it allocates 2N bytes, copies the first N and releases N. You have 3N bytes allocated at some point).
So in the end it has a lot of advantages, and pays of if you know what you are doing. You should know a little of how C++ works to use it on embedded projects without surprises.
And to the guy of the fixed buffers and reset, you can always reset inside the new operator or whatever if you are out of memory, but that would mean you did a bad design that can exhaust your memory.
An exception being thrown with ARM realview 3.1:
--- OSD\#1504 throw fapi_error("OSDHANDLER_BitBlitFill",res);
S:218E72F0 E1A00000 MOV r0,r0
S:218E72F4 E58D0004 STR r0,[sp,#4]
S:218E72F8 E1A02000 MOV r2,r0
S:218E72FC E24F109C ADR r1,{pc}-0x94 ; 0x218e7268
S:218E7300 E28D0010 ADD r0,sp,#0x10
S:218E7304 FA0621E3 BLX _ZNSsC1EPKcRKSaIcE <0x21a6fa98>
S:218E7308 E1A0B000 MOV r11,r0
S:218E730C E1A0200A MOV r2,r10
S:218E7310 E1A01000 MOV r1,r0
S:218E7314 E28D0014 ADD r0,sp,#0x14
S:218E7318 EB05C35F BL fapi_error::fapi_error <0x21a5809c>
S:218E731C E3A00008 MOV r0,#8
S:218E7320 FA056C58 BLX __cxa_allocate_exception <0x21a42488>
S:218E7324 E58D0008 STR r0,[sp,#8]
S:218E7328 E28D1014 ADD r1,sp,#0x14
S:218E732C EB05C340 BL _ZN10fapi_errorC1ERKS_ <0x21a58034>
S:218E7330 E58D0008 STR r0,[sp,#8]
S:218E7334 E28D0014 ADD r0,sp,#0x14
S:218E7338 EB05C36E BL _ZN10fapi_errorD1Ev <0x21a580f8>
S:218E733C E51F2F98 LDR r2,0x218e63ac <OSD\#1126>
S:218E7340 E51F1F98 LDR r1,0x218e63b0 <OSD\#1126>
S:218E7344 E59D0008 LDR r0,[sp,#8]
S:218E7348 FB056D05 BLX __cxa_throw <0x21a42766>
Doesn't seem so scary, and no overhead is added inside {} blocks or functions if the exception isn't thrown.
The biggest problem with STL in embedded systems is the memory allocation issue (which, as you said, causes a lot of problems).
I'd seriously research creating your own memory management, built by overriding the new/delete operators. I'm pretty sure that with a bit of time, it can be done, and it's almost certainly worth it.
As for the exceptions issue, I wouldn't go there. Exceptions are a serious slowdown of your code, because they cause every single block ({ }) to have code before and after, allowing the catching of the exception and the destruction of any objects contained within. I don't have hard data on this on hand, but every time I've seen this issue come up, I've seen overwhelming evidence of a massive slowdown caused by using exceptions.
Edit:
Since a lot of people wrote comments stating that exception handling is not slower, I thought I'd add this little note (thanks for the people who wrote this in comments, I thought it'd be good to add it here).
The reason exception handling slows down your code is because the compiler must make sure that every block ({}), from the place an exception is thrown to the place it is dealt with, must deallocate any objects within it. This is code that is added to every block, regardless of whether anyone ever throws an exception or not (since the compiler can't tell at compile time whether this block will be part of an exception "chain").
Of course, this might be an old way of doing things that has gotten much faster in newer compilers (I'm not exactly up-to-date on C++ compiler optimizations). The best way to know is just to run some sample code, with exceptions turned on and off (and which includes a few nested functions), and time the difference.
On our embedded scanner project we were developing a board with ARM7 CPU and STL didn't bring any issue. Surely the project details are important since dynamic memory allocation may not be an issue for many available boards today and type of projects.

Why doesn't C++ have a garbage collector?

I'm not asking this question because of the merits of garbage collection first of all. My main reason for asking this is that I do know that Bjarne Stroustrup has said that C++ will have a garbage collector at some point in time.
With that said, why hasn't it been added? There are already some garbage collectors for C++. Is this just one of those "easier said than done" type things? Or are there other reasons it hasn't been added (and won't be added in C++11)?
Cross links:
Garbage collectors for C++
Just to clarify, I understand the reasons why C++ didn't have a garbage collector when it was first created. I'm wondering why the collector can't be added in.
Implicit garbage collection could have been added in, but it just didn't make the cut. Probably due to not just implementation complications, but also due to people not being able to come to a general consensus fast enough.
A quote from Bjarne Stroustrup himself:
I had hoped that a garbage collector
which could be optionally enabled
would be part of C++0x, but there were
enough technical problems that I have
to make do with just a detailed
specification of how such a collector
integrates with the rest of the
language, if provided. As is the case
with essentially all C++0x features,
an experimental implementation exists.
There is a good discussion of the topic here.
General overview:
C++ is very powerful and allows you to do almost anything. For this reason it doesn't automatically push many things onto you that might impact performance. Garbage collection can be easily implemented with smart pointers (objects that wrap pointers with a reference count, which auto delete themselves when the reference count reaches 0).
C++ was built with competitors in mind that did not have garbage collection. Efficiency was the main concern that C++ had to fend off criticism from in comparison to C and others.
There are 2 types of garbage collection...
Explicit garbage collection:
C++0x has garbage collection via pointers created with shared_ptr
If you want it you can use it, if you don't want it you aren't forced into using it.
For versions before C++0x, boost:shared_ptr exists and serves the same purpose.
Implicit garbage collection:
It does not have transparent garbage collection though. It will be a focus point for future C++ specs though.
Why Tr1 doesn't have implicit garbage collection?
There are a lot of things that tr1 of C++0x should have had, Bjarne Stroustrup in previous interviews stated that tr1 didn't have as much as he would have liked.
To add to the debate here.
There are known issues with garbage collection, and understanding them helps understanding why there is none in C++.
1. Performance ?
The first complaint is often about performance, but most people don't really realize what they are talking about. As illustrated by Martin Beckett the problem may not be performance per se, but the predictability of performance.
There are currently 2 families of GC that are widely deployed:
Mark-And-Sweep kind
Reference-Counting kind
The Mark And Sweep is faster (less impact on overall performance) but it suffers from a "freeze the world" syndrome: i.e. when the GC kicks in, everything else is stopped until the GC has made its cleanup. If you wish to build a server that answers in a few milliseconds... some transactions will not live up to your expectations :)
The problem of Reference Counting is different: reference-counting adds overhead, especially in Multi-Threading environments because you need to have an atomic count. Furthermore there is the problem of reference cycles so you need a clever algorithm to detect those cycles and eliminate them (generally implement by a "freeze the world" too, though less frequent). In general, as of today, this kind (even though normally more responsive or rather, freezing less often) is slower than the Mark And Sweep.
I have seen a paper by Eiffel implementers that were trying to implement a Reference Counting Garbage Collector that would have a similar global performance to Mark And Sweep without the "Freeze The World" aspect. It required a separate thread for the GC (typical). The algorithm was a bit frightening (at the end) but the paper made a good job of introducing the concepts one at a time and showing the evolution of the algorithm from the "simple" version to the full-fledged one. Recommended reading if only I could put my hands back on the PDF file...
2. Resources Acquisition Is Initialization (RAII)
It's a common idiom in C++ that you will wrap the ownership of resources within an object to ensure that they are properly released. It's mostly used for memory since we don't have garbage collection, but it's also useful nonetheless for many other situations:
locks (multi-thread, file handle, ...)
connections (to a database, another server, ...)
The idea is to properly control the lifetime of the object:
it should be alive as long as you need it
it should be killed when you're done with it
The problem of GC is that if it helps with the former and ultimately guarantees that later... this "ultimate" may not be sufficient. If you release a lock, you'd really like that it be released now, so that it does not block any further calls!
Languages with GC have two work arounds:
don't use GC when stack allocation is sufficient: it's normally for performance issues, but in our case it really helps since the scope defines the lifetime
using construct... but it's explicit (weak) RAII while in C++ RAII is implicit so that the user CANNOT unwittingly make the error (by omitting the using keyword)
3. Smart Pointers
Smart pointers often appear as a silver bullet to handle memory in C++. Often times I have heard: we don't need GC after all, since we have smart pointers.
One could not be more wrong.
Smart pointers do help: auto_ptr and unique_ptr use RAII concepts, extremely useful indeed. They are so simple that you can write them by yourself quite easily.
When one need to share ownership however it gets more difficult: you might share among multiple threads and there are a few subtle issues with the handling of the count. Therefore, one naturally goes toward shared_ptr.
It's great, that's what Boost for after all, but it's not a silver bullet. In fact, the main issue with shared_ptr is that it emulates a GC implemented by Reference Counting but you need to implement the cycle detection all by yourself... Urg
Of course there is this weak_ptr thingy, but I have unfortunately already seen memory leaks despite the use of shared_ptr because of those cycles... and when you are in a Multi Threaded environment, it's extremely difficult to detect!
4. What's the solution ?
There is no silver bullet, but as always, it's definitely feasible. In the absence of GC one need to be clear on ownership:
prefer having a single owner at one given time, if possible
if not, make sure that your class diagram does not have any cycle pertaining to ownership and break them with subtle application of weak_ptr
So indeed, it would be great to have a GC... however it's no trivial issue. And in the mean time, we just need to roll up our sleeves.
What type? should it be optimised for embedded washing machine controllers, cell phones, workstations or supercomputers?
Should it prioritise gui responsiveness or server loading?
should it use lots of memory or lots of CPU?
C/c++ is used in just too many different circumstances.
I suspect something like boost smart pointers will be enough for most users
Edit - Automatic garbage collectors aren't so much a problem of performance (you can always buy more server) it's a question of predicatable performance.
Not knowing when the GC is going to kick in is like employing a narcoleptic airline pilot, most of the time they are great - but when you really need responsiveness!
One of the biggest reasons that C++ doesn't have built in garbage collection is that getting garbage collection to play nice with destructors is really, really hard. As far as I know, nobody really knows how to solve it completely yet. There are alot of issues to deal with:
deterministic lifetimes of objects (reference counting gives you this, but GC doesn't. Although it may not be that big of a deal).
what happens if a destructor throws when the object is being garbage collected? Most languages ignore this exception, since theres really no catch block to be able to transport it to, but this is probably not an acceptable solution for C++.
How to enable/disable it? Naturally it'd probably be a compile time decision but code that is written for GC vs code that is written for NOT GC is going to be very different and probably incompatible. How do you reconcile this?
These are just a few of the problems faced.
Though this is an old question, there's still one problem that I don't see anybody having addressed at all: garbage collection is almost impossible to specify.
In particular, the C++ standard is quite careful to specify the language in terms of externally observable behavior, rather than how the implementation achieves that behavior. In the case of garbage collection, however, there is virtually no externally observable behavior.
The general idea of garbage collection is that it should make a reasonable attempt at assuring that a memory allocation will succeed. Unfortunately, it's essentially impossible to guarantee that any memory allocation will succeed, even if you do have a garbage collector in operation. This is true to some extent in any case, but particularly so in the case of C++, because it's (probably) not possible to use a copying collector (or anything similar) that moves objects in memory during a collection cycle.
If you can't move objects, you can't create a single, contiguous memory space from which to do your allocations -- and that means your heap (or free store, or whatever you prefer to call it) can, and probably will, become fragmented over time. This, in turn, can prevent an allocation from succeeding, even when there's more memory free than the amount being requested.
While it might be possible to come up with some guarantee that says (in essence) that if you repeat exactly the same pattern of allocation repeatedly, and it succeeded the first time, it will continue to succeed on subsequent iterations, provided that the allocated memory became inaccessible between iterations. That's such a weak guarantee it's essentially useless, but I can't see any reasonable hope of strengthening it.
Even so, it's stronger than what has been proposed for C++. The previous proposal [warning: PDF] (that got dropped) didn't guarantee anything at all. In 28 pages of proposal, what you got in the way of externally observable behavior was a single (non-normative) note saying:
[ Note: For garbage collected programs, a high quality hosted implementation should attempt to maximize the amount of unreachable memory it reclaims. —end note ]
At least for me, this raises a serious question about return on investment. We're going to break existing code (nobody's sure exactly how much, but definitely quite a bit), place new requirements on implementations and new restrictions on code, and what we get in return is quite possibly nothing at all?
Even at best, what we get are programs that, based on testing with Java, will probably require around six times as much memory to run at the same speed they do now. Worse, garbage collection was part of Java from the beginning -- C++ places enough more restrictions on the garbage collector that it will almost certainly have an even worse cost/benefit ratio (even if we go beyond what the proposal guaranteed and assume there would be some benefit).
I'd summarize the situation mathematically: this a complex situation. As any mathematician knows, a complex number has two parts: real and imaginary. It appears to me that what we have here are costs that are real, but benefits that are (at least mostly) imaginary.
If you want automatic garbage collection, there are good commercial
and public-domain garbage collectors for C++. For applications where
garbage collection is suitable, C++ is an excellent garbage collected
language with a performance that compares favorably with other garbage
collected languages. See The C++ Programming Language (4rd
Edition) for a discussion of automatic garbage collection in C++.
See also, Hans-J. Boehm's site for C and C++ garbage collection (archive).
Also, C++ supports programming techniques that allow memory
management to be safe and implicit without a garbage collector. I consider garbage collection a last choice and an imperfect way of handling for resource management. That does not mean that it is never useful, just that there are better approaches in many situations.
Source: http://www.stroustrup.com/bs_faq.html#garbage-collection
As for why it doesnt have it built in, If I remember correctly it was invented before GC was the thing, and I don't believe the language could have had GC for several reasons(I.E Backwards compatibilty with C)
Hope this helps.
tl;dr: Because modern C++ doesn't need garbage collection.
Bjarne Stroustrup's FAQ answer on this matter says:
I don't like garbage. I don't like littering. My ideal is to eliminate the need for a garbage collector by not producing any garbage. That is now possible.
The situation, for code written these days (C++17 and following the official Core Guidelines) is as follows:
Most memory ownership-related code is in libraries (especially those providing containers).
Most use of code involving memory ownership follows the CADRe or RAII pattern, so allocation is made on construction and deallocation on destruction, which happens when exiting the scope in which something was allocated.
You do not explicitly allocate or deallocate memory directly.
Raw pointers do not own memory (if you've followed the guidelines), so you can't leak by passing them around.
If you're wondering how you're going to pass the starting addresses of sequences of values in memory - you can and should prefer span's, obviating the need for raw pointers. You can still use such pointers, they'll just be non-owning.
If you really need an owning "pointer", you use C++' standard-library smart pointers - they can't leak, and are decently efficient (although the ABI can get in the way of that). Alternatively, you can pass ownership across scope boundaries with "owner pointers". These are uncommon and must be used explicitly; but when adopted - they allow for nice static checking against leaks.
"Oh yeah? But what about...
... if I just write code the way we used to write C++ in the old days?"
Indeed, you could just disregard all of the guidelines and write leaky application code - and it will compile and run (and leak), same as always.
But it's not a "just don't do that" situation, where the developer is expected to be virtuous and exercise a lot of self control; it's just not simpler to write non-conforming code, nor is it faster to write, nor is it better-performing. Gradually it will also become more difficult to write, as you would face an increasing "impedance mismatch" with what conforming code provides and expects.
... if I reintrepret_cast? Or do complex pointer arithmetic? Or other such hacks?"
Indeed, if you put your mind to it, you can write code that messes things up despite playing nice with the guidelines. But:
You would do this rarely (in terms of places in the code, not necessarily in terms of fraction of execution time)
You would only do this intentionally, not accidentally.
Doing so will stand out in a codebase conforming to the guidelines.
It's the kind of code in which you would bypass the GC in another language anyway.
... library development?"
If you're a C++ library developer then you do write unsafe code involving raw pointers, and you are required to code carefully and responsibly - but these are self-contained pieces of code written by experts (and more importantly, reviewed by experts).
So, it's just like Bjarne said: There's really no motivation to collect garbage generally, as you all but make sure not to produce garbage. GC is becoming a non-problem with C++.
That is not to say GC isn't an interesting problem for certain specific applications, when you want to employ custom allocation and de-allocations strategies. For those you would want custom allocation and de-allocation, not a language-level GC.
Stroustrup made some good comments on this at the 2013 Going Native conference.
Just skip to about 25m50s in this video. (I'd recommend watching the whole video actually, but this skips to the stuff about garbage collection.)
When you have a really great language that makes it easy (and safe, and predictable, and easy-to-read, and easy-to-teach) to deal with objects and values in a direct way, avoiding (explicit) use of the heap, then you don't even want garbage collection.
With modern C++, and the stuff we have in C++11, garbage collection is no longer desirable except in limited circumstances. In fact, even if a good garbage collector is built into one of the major C++ compilers, I think that it won't be used very often. It will be easier, not harder, to avoid the GC.
He shows this example:
void f(int n, int x) {
Gadget *p = new Gadget{n};
if(x<100) throw SomeException{};
if(x<200) return;
delete p;
}
This is unsafe in C++. But it's also unsafe in Java! In C++, if the function returns early, the delete will never be called. But if you had full garbage collection, such as in Java, you merely get a suggestion that the object will be destructed "at some point in the future" (Update: it's even worse that this. Java does not promise to call the finalizer ever - it maybe never be called). This isn't good enough if Gadget holds an open file handle, or a connection to a database, or data which you have buffered for write to a database at a later point. We want the Gadget to be destroyed as soon as it's finished, in order to free these resources as soon as possible. You don't want your database server struggling with thousands of database connections that are no longer needed - it doesn't know that your program is finished working.
So what's the solution? There are a few approaches. The obvious approach, which you'll use for the vast majority of your objects is:
void f(int n, int x) {
Gadget p = {n}; // Just leave it on the stack (where it belongs!)
if(x<100) throw SomeException{};
if(x<200) return;
}
This takes fewer characters to type. It doesn't have new getting in the way. It doesn't require you to type Gadget twice. The object is destroyed at the end of the function. If this is what you want, this is very intuitive. Gadgets behave the same as int or double. Predictable, easy-to-read, easy-to-teach. Everything is a 'value'. Sometimes a big value, but values are easier to teach because you don't have this 'action at a distance' thing that you get with pointers (or references).
Most of the objects you make are for use only in the function that created them, and perhaps passed as inputs to child functions. The programmer shouldn't have to think about 'memory management' when returning objects, or otherwise sharing objects across widely separated parts of the software.
Scope and lifetime are important. Most of the time, it's easier if the lifetime is the same as the scope. It's easier to understand and easier to teach. When you want a different lifetime, it should be obvious reading the code that you're doing this, by use of shared_ptr for example. (Or returning (large) objects by value, leveraging move-semantics or unique_ptr.
This might seem like an efficiency problem. What if I want to return a Gadget from foo()? C++11's move semantics make it easier to return big objects. Just write Gadget foo() { ... } and it will just work, and work quickly. You don't need to mess with && yourself, just return things by value and the language will often be able to do the necessary optimizations. (Even before C++03, compilers did a remarkably good job at avoiding unnecessary copying.)
As Stroustrup said elsewhere in the video (paraphrasing): "Only a computer scientist would insist on copying an object, and then destroying the original. (audience laughs). Why not just move the object directly to the new location? This is what humans (not computer scientists) expect."
When you can guarantee only one copy of an object is needed, it's much easier to understand the lifetime of the object. You can pick what lifetime policy you want, and garbage collection is there if you want. But when you understand the benefits of the other approaches, you'll find that garbage collection is at the bottom of your list of preferences.
If that doesn't work for you, you can use unique_ptr, or failing that, shared_ptr. Well written C++11 is shorter, easier-to-read, and easier-to-teach than many other languages when it comes to memory management.
The idea behind C++ was that you would not pay any performance impact for features that you don't use. So adding garbage collection would have meant having some programs run straight on the hardware the way C does and some within some sort of runtime virtual machine.
Nothing prevents you from using some form of smart pointers that are bound to some third-party garbage collection mechanism. I seem to recall Microsoft doing something like that with COM and it didn't go to well.
To answer most "why" questions about C++, read Design and Evolution of C++
One of the fundamental principles behind the original C language is that memory is composed of a sequence of bytes, and code need only care about what those bytes mean at the exact moment that they are being used. Modern C allows compilers to impose additional restrictions, but C includes--and C++ retains--the ability to decompose a pointer into a sequence of bytes, assemble any sequence of bytes containing the same values into a pointer, and then use that pointer to access the earlier object.
While that ability can be useful--or even indispensable--in some kinds of applications, a language that includes that ability will be very limited in its ability to support any kind of useful and reliable garbage collection. If a compiler doesn't know everything that has been done with the bits that made up a pointer, it will have no way of knowing whether information sufficient to reconstruct the pointer might exist somewhere in the universe. Since it would be possible for that information to be stored in ways that the computer wouldn't be able to access even if it knew about them (e.g. the bytes making up the pointer might have been shown on the screen long enough for someone to write them down on a piece of paper), it may be literally impossible for a computer to know whether a pointer could possibly be used in the future.
An interesting quirk of many garbage-collected frameworks is that an object reference not defined by the bit patterns contained therein, but by the relationship between the bits held in the object reference and other information held elsewhere. In C and C++, if the bit pattern stored in a pointer identifies an object, that bit pattern will identify that object until the object is explicitly destroyed. In a typical GC system, an object may be represented by a bit pattern 0x1234ABCD at one moment in time, but the next GC cycle might replace all references to 0x1234ABCD with references to 0x4321BABE, whereupon the object would be represented by the latter pattern. Even if one were to display the bit pattern associated with an object reference and then later read it back from the keyboard, there would be no expectation that the same bit pattern would be usable to identify the same object (or any object).
SHORT ANSWER:
We don't know how to do garbage collection efficiently (with minor time and space overhead) and correctly all the time (in all possible cases).
LONG ANSWER:
Just like C, C++ is a systems language; this means it is used when you are writing system code, e.g., operating system. In other words, C++ is designed, just like C, with best possible performance as the main target. The language' standard will not add any feature that might hinder the performance objective.
This pauses the question: Why garbage collection hinders performance? The main reason is that, when it comes to implementation, we [computer scientists] do not know how to do garbage collection with minimal overhead, for all cases. Hence it's impossible to the C++ compiler and runtime system to perform garbage collection efficiently all the time. On the other hand, a C++ programmer, should know his design/implementation and he's the best person to decide how to best do the garbage collection.
Last, if control (hardware, details, etc.) and performance (time, space, power, etc.) are not the main constraints, then C++ is not the right tool. Other language might serve better and offer more [hidden] runtime management, with the necessary overhead.
All the technical talking is overcomplicating the concept.
If you put GC into C++ for all the memory automatically then consider something like a web browser. The web browser must load a full web document AND run web scripts. You can store web script variables in the document tree. In a BIG document in a browser with lots of tabs open, it means that every time the GC must do a full collection it must also scan all the document elements.
On most computers this means that PAGE FAULTS will occur. So the main reason, to answer the question is that PAGE FAULTS will occur. You will know this as when your PC starts making lots of disk access. This is because the GC must touch lots of memory in order to prove invalid pointers. When you have a bona fide application using lots of memory, having to scan all objects every collection is havoc because of the PAGE FAULTS. A page fault is when virtual memory needs to get read back into RAM from disk.
So the correct solution is to divide an application into the parts that need GC and the parts that do not. In the case of the web browser example above, if the document tree was allocated with malloc, but the javascript ran with GC, then every time the GC kicks in it only scans a small portion of memory and all PAGED OUT elements of the memory for the document tree does not need to get paged back in.
To further understand this problem, look up on virtual memory and how it is implemented in computers. It is all about the fact that 2GB is available to the program when there is not really that much RAM. On modern computers with 2GB RAM for a 32BIt system it is not such a problem provided only one program is running.
As an additional example, consider a full collection that must trace all objects. First you must scan all objects reachable via roots. Second scan all the objects visible in step 1. Then scan waiting destructors. Then go to all the pages again and switch off all invisible objects. This means that many pages might get swapped out and back in multiple times.
So my answer to bring it short is that the number of PAGE FAULTS which occur as a result of touching all the memory causes full GC for all objects in a program to be unfeasible and so the programmer must view GC as an aid for things like scripts and database work, but do normal things with manual memory management.
And the other very important reason of course is global variables. In order for the collector to know that a global variable pointer is in the GC it would require specific keywords, and thus existing C++ code would not work.
When we compare C++ with Java, we see that C++ was not designed with implicit Garbage Collection in mind, while Java was.
Having things like arbitrary pointers in C-Style is not only bad for GC-implementations, but it would also destroy backward compatibility for a large amount of C++-legacy-code.
In addition to that, C++ is a language that is intended to run as standalone executable instead of having a complex run-time environment.
All in all:
Yes it might be possible to add Garbage Collection to C++, but for the sake of continuity it is better not to do so.
Mainly for two reasons:
Because it doesn't need one (IMHO)
Because it's pretty much incompatible with RAII, which is the cornerstone of C++
C++ already offers manual memory management, stack allocation, RAII, containers, automatic pointers, smart pointers... That should be enough. Garbage collectors are for lazy programmers who don't want to spend 5 minutes thinking about who should own which objects or when should resources be freed. That's not how we do things in C++.
Imposing garbage collection is really a low level to high level paradigm shift.
If you look at the way strings are handled in a language with garbage collection, you will find they ONLY allow high level string manipulation functions and do not allow binary access to the strings. Simply put, all string functions first check the pointers to see where the string is, even if you are only drawing out a byte. So if you are doing a loop that processes each byte in a string in a language with garbage collection, it must compute the base location plus offset for each iteration, because it cannot know when the string has moved. Then you have to think about heaps, stacks, threads, etc etc.