|
![](/i/fill.gif) |
Darren New <dne### [at] san rr com> wrote:
> > (In principle RAII is not incompatible with garbage collection, so
> > conceivably you could have both in the same language.)
> Indeed. Especially if you use something like reference counting and deal
> with circular references specially or something.
What I meant is that, for example in C++, it's possible to have value
semantics for objects as well as reference (well, pointer) semantics for
objects, and these can be kept pretty much separate. Then you can have
RAII (iow. scope-based lifetime) semantics on the objects and GC on the
references. There are, in fact, GC engines for C++ which work like this
(basically, anything you allocate dynamically with 'new' can be GC'd,
while anything you allocate without it uses regular RAII semantics).
On a different note, one example where I think the RAII mechanism is
better than the Java-style GC mechanism is that RAII allows you to
implement copy-on-write semantics (ie. "lazy copying") for objects.
In other words, if you have some object with potentially lots of data,
and you want to use copy semantics for it (ie. if you assign the object
to another, the latter gets a copy of the data rather than sharing the
data), copy-on-write makes the copying lazily, only if needed (ie. only
if one of the copies tries to modify the data).
For instance, assume that std::string used copy-on-write (which it does
in some implementations). If you write this:
std::vector<std::string> strings(1000, "hello there");
you will have a vector of 1000 strings, each one with the value "hello
there". However, the actual "hello there" data is shared among all the
strings and hence stored in memory only once (which may become a significant
saving if it would be kilobytes or megabytes of data instead of just 11
characters). However, if you now do something like:
strings[250] += ", world";
only the 251st string in the vector will be converted to "hello there, world"
rather than all of them. The rest of the string will still share that one
and same data, and only the 251st string will now have its own copy of the
data, with more data appended.
What happened there is that the 251st string made a deep-copy of the data
before modifying it, thus preventing any of the other strings from changing.
Of course if you now modify it again:
strings[250] += "!";
it will *not* perform a needless deep-copy of the data because the current
data is not shared. In other words, it will deep-copy the data only when
needed.
And most importantly, it will do that completely transparently. You can't
see that from the outside. From the outside std::string simply has copy
semantics and that's it. You could compile the program with a different
implementation of std::string which does not use CoW, and it would still
work the same (except, obviously, now consuming more memory).
Of course CoW requires reference counting of the data (or, more precisely,
it needs a way to tell if the data is being shared or not). I don't know
how you would do that in Java (transparently, or at all).
This is possible transparently in C++ because of RAII: When objects are
created, copied, assigned and destroyed, you can specify what happens.
This allows you to keep a reference count on the data handled by the class.
(And note that I'm not saying there aren't advantages with a GC system
like the one in Java, including efficiency benefits in some situations.)
--
- Warp
Post a reply to this message
|
![](/i/fill.gif) |