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