Does anyone know of a good compiler for c++ that supports garbage collection. I know that they were considering it for c++11 but didn't implement it.
2 Answers
One of the most-often heard of approaches is to use Hans Boehm's GC, which can be plugged into C++. Of course, an alternative is to use smart pointers that keep track of the use of objects.
For everybody who upvoted the "who needs this" comment, the answer is that it can be more expensive:
- Imagine that you fork() your program and now start adjusting refcounters in objects that remain constant otherwise. This will cause performance overhead because it means that the OS can't share the memory between the two processes, i.e. it breaks copy-on-write. In some cases, it can mean that the OS has to swap in memory only to copy and adjust reference counters.
- Another example is something like the suggested
boost::shared_ptr. Each of these has an additional allocation as overhead in order to store the reference counter, weak reference counter and deleter. This doesn't come for free either. Further, an instance thereof has twice the size of a pointer. - Then, if you use a normal size_t for the refcounter and built-in increment/decrement, your code isn't multithreading safe. However, if you use atomic integers, incrementing and decrementing takes much more time to flush caches and because it disallows reordering. Remember, every time you copy such a pointer, you have to increment the reference counter. Every time one instance is destroyed, you have to decrement the counter again. Maintaining a reference count can accumulate to much higher overhead that using a mark-and-sweep GC to count references now and then.
- Lastly, refcounted pointers need the programmer to actively consider the possibility of cycles. GCs can detect and break cycles automatically.
If you keep the above in mind, a GC is an alternative. It does have disadvantages, like non-deterministic cleanup, but Java and C# show that you can live with this and there is nothing that keeps you from programming it yourself in those places where you really need it.
4 Comments
std::make_shared avoids the additional allocation, it coalesces the two. This improves locality of reference and reduces fragmentation. This also reduces the penalty of cache flushes, as the object is often flushed alongside its count. (3rd bullet). Of course, if you use fork, this sharing amplifies the COW problem.std::basic_strings requirements...)operator[], whereas the page copy happens only on a physical write, blocks only the writing thread, and is optimally (page) aligned.fork, you can create your own make_shared_fork<T> that keeps all counter in one memory pool and all constant objects in another. That way, the first COW will copy all counters and only the counters.Usually, you can get around fine using RAII and smart pointers (such as shared_ptr and unique_ptr in C++11).
However, if you need garbage collection, look into Boehm's garbage collector. You could overload operator new as following.
enum GCPlacement { NoGC, GC, }; void* operator new(size_t size, GCPlacement gcp) { void* toReturn; if (gcp == GC) toReturn = GC_MALLOC(size); else toReturn = GC_MALLOC_UNCOLLECTABLE(size); if (!toReturn) throw std::bad_alloc(); else return toReturn; } void operator delete(void* p, GCPlacement) { GC_FREE(p); } Now, you can allocate garbage collected memory as following:
Object* o = new (GC) Object(); If you want, you can also derive certain classes from the gc class provided by boehmgc to indicate these should always be allocated using garbage collection.
C++/CLI is another solution, but be advised that it technically is not C++ (it is an extension of a partial implementation of C++) and it ties you to the Microsoft/.NET platform -- essentially, it's just C# with a C++ syntax.
std::unique_ptr. That's the one you should be using by default.