Thread overview
weird behave of Array?
Jul 28, 2019
dmm
Jul 28, 2019
Adam D. Ruppe
Jul 28, 2019
Adam D. Ruppe
Jul 29, 2019
dmm
Jul 29, 2019
FeepingCreature
July 28, 2019
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?
July 28, 2019
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).

July 28, 2019
BTW If you want those length changes to be seen in the original, pass the array by ref to the functions doing the changes.
July 29, 2019
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?
July 29, 2019
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);
}