C++ – Disadvantages of scoped-based memory management

cgarbage-collectionlanguage-designprogramming-languagesraii

I really like scope-based memory management (SBMM), or RAII, as it is more commonly (confusingly?) referred to by the C++ community. As far as I know, except for C++ (and C), there's no other mainstream language in use today that makes SBMM/RAII their main memory management mechanism, and instead they prefer to use garbage collection (GC).

I find this rather confusing, since

  1. SBMM makes programs more deterministic (you can tell exactly when an object is destroyed);
  2. in languages that use GC you often have to do manual resource management (see closing files in Java, for example), which partly defeats the purpose of GC and is also error prone;
  3. heap memory can also (very elegantly, imo) be scope-bound (see std::shared_ptr in C++).

Why is not SBMM more widely used? What are its disadvantages?

Best Answer

Let's start by postulating that memory is by far (dozens, hundreds or even thousands of time) more common than all other resources combined. Every single variable, object, object member needs some memory allocated to it and freed later on. For every file you open, you create dozens to millions of objects to store the data pulled out of the file. Every TCP stream goes together with an unbounded number of temporary byte strings created to be written to the stream. Are we on the same page here? Great.

For RAII to work (even if you have ready-made smart pointers for every use case under the sun), you need to get ownership right. You need to analyse who should own this or that object, who should not, and when ownership should be transferred from A to B. Sure, you could use shared ownership for everything, but then you'd be emulating a GC via smart pointers. At that point it becomes much easier and faster to build the GC into the language.

Garbage collection frees you from this concern for the by far most commonly used resource, memory. Sure, you still need to make the same decision for other resources, but those are far less common (see above), and complicated (e.g. shared) ownership is less common too. The mental burden is reduced significantly.

Now, you name some downsides to making all values garbage collected. However, integrating both memory-safe GC and value types with RAII into one language is extremely hard, so perhaps it's better to migitate these trade offs via other means?

The loss of determinism in turns out to be not that bad in practice, because it only affects deterministic object lifetime. As described in the next paragraph, most resources (aside from memory, which is plentiful and can be recycled rather lazily) are not bound to object lifetime in these languages. There are a few other uses cases, but they are rare in my experience.

Your second point, manual resource management, is nowadays addressed via a statement that does perform scope-based cleanup, but does not couple this clean up to the object life time (hence not interacting with the GC and memory safety). This is using in C#, with in Python, try-with-resources in recent Java versions.