www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - weird behave of Array?

reply dmm <dmm test.com> writes:
import std.stdio : writefln;

void test(string str)
{
   writefln("%d, %d", str.length, str.capacity);
   str.length = 10;
   writefln("%d, %d", str.length, str.capacity);
}

void main()
{
   string str;
   str.reserve(1024);
   //str.length = str.capacity;
   writefln("%d, %d", str.length, str.capacity);
   test(str);
   writefln("%d, %d", str.length, str.capacity);
}

The output is:

0, 1358
0, 1358
10, 1358
0, 0

If I uncomment the line str.length = str.capacity;

then the output is:

1358, 1358
1358, 1358
10, 0
1358, 1358

why?
Jul 28 2019
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Sunday, 28 July 2019 at 17:21:25 UTC, dmm wrote:
   test(str);
The array is passed by value here, so changes to its ptr and length will not be seen outside the function. However, what goes *through* the pointer - which includes the contents and the capacity - will be seen. The runtime tries to minimize weird stuff by opting for making the capacity 0 if the array structure has been modified in a function (so of the length is changed, if it is appended, etc.), so then appends will not stomp over contents from two different locations. Since the memory pointed to is a shared resource it is conservative in not reusing it. You can read a bit more about this here https://dlang.org/articles/d-array-article.html#append-on (really the whole article might be good background).
Jul 28 2019
next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
BTW If you want those length changes to be seen in the original, 
pass the array by ref to the functions doing the changes.
Jul 28 2019
prev sibling parent reply dmm <dmm test.com> writes:
On Sunday, 28 July 2019 at 17:45:16 UTC, Adam D. Ruppe wrote:
 On Sunday, 28 July 2019 at 17:21:25 UTC, dmm wrote:
   test(str);
The array is passed by value here, so changes to its ptr and length will not be seen outside the function. However, what goes *through* the pointer - which includes the contents and the capacity - will be seen. The runtime tries to minimize weird stuff by opting for making the capacity 0 if the array structure has been modified in a function (so of the length is changed, if it is appended, etc.), so then appends will not stomp over contents from two different locations. Since the memory pointed to is a shared resource it is conservative in not reusing it. You can read a bit more about this here https://dlang.org/articles/d-array-article.html#append-on (really the whole article might be good background).
So, d try to be smart, only make thing worse? the following code, it keeping realloc when call reset. this won't happend in cpp if call vector.resize under capacity. import std.stdio : writefln; class Lexer { ubyte[] buf; this() { buf.reserve(1024); writefln("%x, %d, %d", buf.ptr, buf.length, buf.capacity); } void doSomething() { buf.length = 1024; } void reset() { buf.length = 0; writefln("%x, %d, %d", buf.ptr, buf.length, buf.capacity); } } void main() { Lexer l = new Lexer(); l.doSomething(); l.reset(); l.doSomething(); l.reset(); } BTW, why call reserve(1024) got capacity at 1358? isn't reserve(n) means capacity = length + n? how do you set capacity to 2 ^ n?
Jul 28 2019
parent FeepingCreature <feepingcreature gmail.com> writes:
On Monday, 29 July 2019 at 05:58:21 UTC, dmm wrote:
 So, d try to be smart, only make thing worse?
D is behaving exactly as it should here. You simply have a wrong model of what an array is in D. In C++, an array owns its memory. In D, an array is a thin wrapper around GC managed memory. As such, for instance, you can take a reference to an array field, then resize the array, and the original reference will still be valid and at its original value. To do what you want, use std.array.Appender, which owns its memory. import std.algorithm; import std.array; import std.range; import std.stdio; void main() { Appender!(int[]) app; 10.iota.each!(a => app.put(a)); writefln!"%s, %s"(app.data.ptr, app.data); app.shrinkTo(0); 10.iota.each!(a => app.put(a)); writefln!"%s, %s"(app.data.ptr, app.data); }
Jul 29 2019