Array slices and copy on write
Jonathan M Davis
jmdavisProg at gmx.com
Sun Apr 3 16:14:34 PDT 2011
On 2011-04-03 07:29, simendsjo wrote:
> On 03.04.2011 14:55, spir wrote:
> > On 04/03/2011 02:29 PM, simendsjo wrote:
> >> D will copy the original content if a slice expands, but is the
> >> following behavior
> >> implementation specific, or part of the specification?
> >>
> >> auto a = [0,1,2];
> >> auto b = a[0..2];
> >> a.length = 2; // is a[3] already marked for collection by the gc?
> >> assert(a.ptr == b.ptr);
> >> b.length += 1; // as b cannot reuse it even though noone is using it
> >> assert(a.ptr == b.ptr); // ooops, fails.. b is reallocated
> >
> > As I understand it (there is no real spec for D), this is consistent
> > with the often commented design of D slices.
> > People often explain that slices are like views on (implicite or
> > explicit) ordinary arrays. Then, change on either is seen by both, just
> > like references --*except* when change require resizing.
> > Another point of view is that slices somewhat work like copy-on-write:
> > there is no actual copy until one variable value is changed, then only
> > copy happens --expect when change can happen on place.
> >
> > Denis
>
> I know the dangers of slices and copy on write. I was thinking of a very
> specific example. I'll try to explain better.
>
> auto a = [0,1,2];
> auto b = a[0..2];
> a.length = 2;
> // a[3] should now not be referenced, but my guess is it's not collected
> by the gc
> assert(a.ptr == b.ptr);
> b.length += 1;
> // b could potentionally use the last part of a instead of reallocating
> // Could another implementation reuse a's old memory without reallocating?
What the GC does and doesn't choose to collect is implementation-specific and
doesn't necessarily have anything to do with the compiler. Also, remember that
memory allocation is done in blocks, so there's pretty much no way that the
last element of an array would be collected simply because you shrunk the
length of the array by one. And you may not want it to anyway. There is at
least a chance that b.length += 1 would cause b to use the now unreferenced
3rd element of a, so giving that one element's worth of memory to the OS could
be very ineffecient. Regardless, whether b.length +=1 manages to avoid a
reallocation is implementation-dependent.
You should _not_ generally rely on when you are or aren't going to get a
memory reallocation with an array. If you want to guarantee that a
reallocation takes place, use dup or idup. If you want to guarantee that one
doesn't take place, then don't increase the size of any array/slice which
points to a particular block of memory. Beyond that, you don't really have any
guarantees about reallocation. druntime will guarantee that you don't end up
with your arrays stomping on each other, and it will try and minimize
reallocations, but how it does all that is implementation-dependent.
- Jonathan M Davis
More information about the Digitalmars-d-learn
mailing list