std.container and classes

Jacob Carlborg doob at me.com
Tue Dec 20 23:44:10 PST 2011


On 2011-12-21 06:07, Jonathan M Davis wrote:
> On Monday, December 19, 2011 08:54:00 Jacob Carlborg wrote:
>> The Tango runtime has added a new method in Object, "dispose". This
>> method is called when "scope" is used or "delete" is explicitly called.
>> I don't know if that would help.
>
> That sounds a lot like using clear, though clear doesn't free memory unless
> the finalizer does (and I'm not sure that managing memory with finalizers
> actually works right now; there were issues with that previously - but it
> might have only been GC memory, so perhaps malloc and free would still work).
> The issue with them is escaping references. You can easily end up with
> references to data which has been destroyed. It also makes them harder to pass
> around unless you essentially wrap the container in ref-counted struct.
>
> The lifetime of the container must be managed if you really want to be able to
> use custom allocators or have the container be as efficient as possible with
> regards to its memory usage in the general case. With a struct, it manages
> itself. It can do whatever it wants to with memory internally, and the
> combination of its constructor, postblit constructor, and destructor allows it
> to take care of it itself and clean up its memory when it's destroyed. You
> also don't have issues of stuff referring to a container which doesn't exist
> anymore (unless you add pointers to the container into the mix and then move
> or destroy the container).
>
> With classes, if they're owned by the GC, then it's the GC that manages their
> lifetime. It destroys them when they're no longer referenced and it runs a
> collection cycle. You have no control over its lifetime, and even if it tries
> to manage its memory internally on some level, that memory won't be cleaned up
> until the GC collects the container itself. So, if you want to manage the
> lifetime of the class, you can't use a naked reference anymore. You need a way
> to get the GC to collect it, or you need to have it somewhere else other than
> the GC heap.

With "dispose" it would give you the option to control the lifetime of 
the object, in some cases.

> If you use something like Scoped, then its lifetime will be tied to the scope
> that it's in, but you risk references to it escaping, and limiting the
> container to a particular scope could be far too limiting anyway. That being
> the case, if you want to use an allocator other than the GC for the class
> itself, then you're probably going to have to stick it in a struct. That
> struct could then manage the container's lifetime on some level. It would
> probably have to use ref-counting and then call clear on the container when
> the ref-count hits zero. That should then allow the container to at least
> clean up its internal memory, assuming that that's not on the GC heap, but
> unless you use emplace on non-GC heap memory, the container itself still can't
> be collected until the GC collects it (since clear destroys it but doesn't
> free its memory). Not to mention, if you're using a ref-counted struct to hold
> a class in order to manage that class' lifetime, why on earth did you make it
> a class in the first place?
>
> If what you're suggesting with dispose is that it would act like clear except
> that it would actually free the container, well that pretty much goes against
> the direction that we've been trying to go with the GC, which is to not have
> the programmer explicitly freeing anything on the GC heap (which is why delete
> is being removed from the language).

I thought that one of the problems with the GC and memory was that you 
can't rely on when/if the destructors are called. With "dispose" it 
would give the developer a reliable method to cleanup resources, 
assuming "scope" or "delete" is used.

> I really think that if we want deterministic destruction of containers, they
> need to be structs. And if we want to use custom allocators with containers, I
> don't see how we could reasonably expect them to be of much use unless we're
> expecting that programmers will explicitly call clear on them when they're
> done with them. So, while the fact that containers need to be reference types
> does imply that classes are the way to go, I think that we're going to have to
> go with structs if we want their memory management to be more efficient than
> simply letting the GC handle it.
>
> - Jonathan M Davis

I was thinking that classes could be the safe and default but and 
scope/delete could be used as an optimization.

-- 
/Jacob Carlborg


More information about the Digitalmars-d mailing list