Array length & allocation question

Oskar Linde oskar.lindeREM at OVEgmail.com
Tue Jun 13 00:24:34 PDT 2006


Derek Parnell skrev:
> On Tue, 13 Jun 2006 01:05:04 +0200, Oskar Linde wrote:
> 
>>> Setting the length to zero is a convenient way to reserved RAM for an 
>>> array.
>> t arr.length = 100_000_000; arr = arr[0..0]; is almost as convenient.
> 
> Unfortunately this only appears to reserve the RAM, because the next change
> in length will cause a new allocation to be made. See the example program
> below ...
>  
>>> Also consider this ...
>>>
>>>     foo("");
>>>
>>> Now how can 'foo' be written to detect a coder's error of passing it an 
>>> uninitialized array.
>>>
>>>     char[] x;
>>>     foo(x);
>>>
>> Like this:
>>
>> void foo(char[] arr) {
>> 	if (!arr)
>> 		writefln("Uninitialized array passed");
>> 	else if (arr.length == 0)
>> 		writefln("Zero length array received");
>> }
> 
> Yes, I can see that D can now distinguish between the two. This didn't used
> to be the case, IIRC. However there is still a 'bug' with this as the
> program here demonstrates...
> 
> 
>  import std.stdio;
>  void main()
>  { 
> 
>     char[] arr;
> 
>     foo(arr);
>     foo("");
>     foo("".dup);
> 
>     writefln("%s %s", arr.length, arr.ptr);
>     arr.length = 100;
>     writefln("%s %s", arr.length, arr.ptr);
>     arr = arr[0..0];
>     writefln("%s %s", arr.length, arr.ptr);
>     arr.length = 50;
>     writefln("%s %s", arr.length, arr.ptr);
>     arr.length = 500;
>     writefln("%s %s", arr.length, arr.ptr);
>  
>  }
> 
>  void foo(char[] t)
>  {
>     writefln("foo: %s %s", t.length, t.ptr);
>  }
> 
> The results are ...
> foo: 0 0000
> foo: 0 413080
> foo: 0 0000  *** A 'dup'ed empty string is now a null string.
> 0 0000
> 100 8A2F00
> 0 8A2F00   *** RAM appears to be reserved.
> 50 8A1F80  *** But it is not as a new allocation just occurred.
> 500 8A3E00 *** This allocation is expected.

You are right, changing length forces a reallocation. Interestingly, the 
following works:

arr.length = 100;
arr = arr[0..0];
writefln("%s %s",arr.length,arr.ptr);
for (int i = 0; i < 50; i++)
	arr ~= i;
writefln("%s %s",arr.length,arr.ptr);

prints (for me):

0 b7ee9e00
50 b7ee9e00

What is even more interesting is that the above "buggy" behavior seems 
intentional. The following patch removes the forced reallocation when 
changing length of a 0-length array:

--- gc.d.orig   2006-06-04 11:50:08.979945284 +0200
+++ gc.d        2006-06-13 09:19:02.135348959 +0200
@@ -382,8 +382,6 @@
         }
         //printf("newsize = %x, newlength = %x\n", newsize, newlength);

-       if (p.length)
-       {
             newdata = p.data;
             if (newlength > p.length)
             {
@@ -397,11 +395,6 @@
                 }
                 newdata[size .. newsize] = 0;
             }
-       }
-       else
-       {
-           newdata = cast(byte *)_gc.calloc(newsize + 1, 1);
-       }
      }
      else
      {


With this change, your above code prints:

$build -run ./arrtest ~/dmd/src/phobos/internal/gc/gc.d
Path and Version : build v2.9(1197)
   built on Thu Aug 11 16:07:55 2005
foo: 0 0
foo: 0 805765c
foo: 0 0
0 0
100 b7ee8e80
0 b7ee8e80    *** RAM is reserved
50 b7ee8e80   *** and is used
500 b7ee9e00  *** This causes reallocation as expected

I wonder why the code looks like it does...

/Oskar



More information about the Digitalmars-d-learn mailing list