Hacker News new | past | comments | ask | show | jobs | submit login

Right. I could also have said “If GC were all you need, no one would be using RAII in the first place”. No contradiction here.

So it can make sense for a library to support both, to accommodate different application needs.




How would you write a library to support both without being fully RAII correct? And if it's fully RAII correct, isn't the GC is a no-op?


You would usually do it for performance rather than RAII correctness.

For example, without GC, your library might use RAII with std::shared_ptr, for certain objects that outlive lexical scope. That is, reference counts tied to pointer copies and destructors. With GC, your library might omit the reference counts when deferred object destruction is ok, saving a little space and time.

If your library is dealing with something like a graph (nodes connected by pointers) which may have cycles, std::shared_ptr will not be enough to free all objects as they become unused, but the environment GC will do it. Therefore, without an environment GC, your graph-using library will need its own cycle detector, or if usage permits, something with arenas or std::weak_ptr. With GC, your graph-using library can omit that code entirely.

There are occasions when you'd want to add code for correctness when using a GC, to release objects by clearing pointers to them in some circumstances where it's safe to leave the pointer uncleared (and possibly invalid but harmless) without GC.


There are several ways I can think of. For example, a library that stores application-provided elements (e.g. a graph library where nodes/edges can carry application-specific data) can support by-value RAII elements as well as by-reference GC’d elements and by-reference library-memory-managed elements (using new/delete). As another example, the destructor of a library-provided class might have to free a complex internal heap-based substructure, a potentially expensive operation (having to iterate over the substructure) that it can skip (only) when running under a GC.


That's kinda the point: you can't skip it with RAII, unless you avoid exiting a scope (longjmp?).

I suppose you can have two versions of the class, and instantiate the leaky one only if you have GC, but that seems like work that the GC should free you from. It seems better to optimize the memory allocations, perhaps with an arena.


Not sure what you mean. My point is, for the case of no GC, you have to provide a destructor, even if the work done by the destructor only consists of freeing memory. With GC, calling the destructor could be omitted if it only frees memory. Client code however doesn’t know what a destructor does internally, so always has to call it even under a GC. The implementation of the destructor, however, can check whether it is running under a GC, and can then skip the freeing.

Edit due to your edit: An arena allocator isn’t always convenient, for example when you have multiple objects with different lifetimes that move and/or partially share internal elements between them, so the element lifetimes are largely orthogonal to the containing object’s lifetimes.


> My point is, for the case of no GC, you have to provide a destructor, even if the work done by the destructor only consists of freeing memory.

for the case of no GC, a destructor must be provided. That's an important difference.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: