Memory leak with dynamic array

Steven Schveighoffer schveiguy at yahoo.com
Sat Apr 10 17:43:44 PDT 2010


On Sat, 10 Apr 2010 18:17:12 -0400, bearophile <bearophileHUGS at lycos.com>  
wrote:

> This can help confuse your mind a bit:
>
> import std.stdio: writeln;
> void main() {
>     {
>         int[] arr = [0, 1, 2, 3, 4, 5, 6].dup;
>         int[] slice = arr[2 .. 4];
>         writeln("arr, slice: ", arr, " | ", slice); // arr, slice: 0 1 2  
> 3 4 5 6 | 2 3
>         slice ~= 10; slice ~= 20;
>         writeln("arr.capacity, slice.capacity: ", arr.capacity, " ",  
> slice.capacity); // arr.capacity, slice.capacity: 7 7
>         writeln("arr, slice: ", arr, " | ", slice); // arr, slice: 0 1 2  
> 3 4 5 6 | 2 3 10 20
>     }
>
>     {
>         int[] arr = [0, 1, 2, 3, 4, 5, 6].dup;
>         int[] slice = arr[2 .. 4];
>         writeln("arr, slice: ", arr, " | ", slice); // arr, slice: 0 1 2  
> 3 4 5 6 | 2 3
>
>         slice.assumeSafeAppend;
>         slice ~= 10; slice ~= 20; // causes stomping
>         writeln("arr.capacity, slice.capacity: ", arr.capacity, " ",  
> slice.capacity); // arr.capacity, slice.capacity: 0 5
>         writeln("arr, slice: ", arr, " | ", slice); // arr, slice: 0 1 2  
> 3 10 20 6 | 2 3 10 20
>         slice ~= 30; slice ~= 40;
>         writeln("arr.capacity, slice.capacity: ", arr.capacity, " ",  
> slice.capacity); // arr.capacity, slice.capacity: 7 7
>         writeln("arr, slice: ", arr, " | ", slice); // arr, slice: 0 1 2  
> 3 10 20 30 | 2 3 10 20 30 40
>     }
> }
>
>
> The  slice.capacity = 7 in the first case is just a coincidence, it's  
> the result of the overallocation.

Yes, to allocate an array of 4 integers, you need 16 bytes, but there  
needs to be a padding byte to prevent cross-block pointer problems, so it  
uses a 32-byte block.  The 32-byte block also needs a padding byte, so  
really you can only put in 7 elements, not 8.

> But I don't know why arr.capacity is zero and then seven in the second  
> and third case.

0 means if you append to the array, it will reallocate.  It will return 0  
for stack-allocated arrays also.  This makes sense since the slice has  
taken over the "allocated" length of the block.  Essentially, capacity  
indicates how many elements can be appended.  The function gives up and  
returns 0 if it determines the array does not end at the allocated part of  
a block.  Technically, I could return the length of the array, but I'm not  
sure whether that is as useful.

For fun, add one more element to slice, and the arr will now have a valid  
capacity :)

FYI, using arr after assuming safe append on the slice is undefined.

-Steve


More information about the Digitalmars-d-learn mailing list