static array internal & dangling reference
Mike Parker via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Sat Nov 12 03:03:31 PST 2016
On Saturday, 12 November 2016 at 10:33:05 UTC, Picaud Vincent
wrote:
> Hi all,
> Still learning... This time what surprised me is how static
> arrays work.
> I assume (is it true?) that for efficiency reason static size
> arrays like int[10] are on the stack and do not involve dynamic
> memory allocation:
Yes, they are on the stack. That's what the 'static' in 'static
array' implies. The same is true in C and C++ (and other
programming languages that distinguish between static and dynamic
arrays). It's why their length is fixed and known at compile time.
>
> First surprise: it is possible to share a static array:
>
> void main() {
>
> int[10] sa;
> foreach(int i, ref sa_i;sa){
> sa_i=i;
> }
> writeln("\n vect init sa",sa);
>
> int[] sb=sa[3..6]; // <- did not think it was possible
> sb[2]=100;
>
> writeln("\n vect sa ",sa);
> writeln("\n vect sb ",sb);
> }
>
> which prints:
>
> vect init sa[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>
> vect sa [0, 1, 2, 3, 4, 100, 6, 7, 8, 9] // <- sa and sb are
> really shared
sb is a slice of sa. A slice *always* shares the memory block
backing the original array until the slice is reallocated, which
on a fresh slice of an existing array is pretty much always going
to happen as soon as you append to it.
>
> Second surprise: I tried to create a dangling reference with:
>
> int[] f()
> {
> int[10] sa;
> foreach(int i, ref sa_i;sa){
> sa_i=i;
> }
> int[] sb=sa;
> return sb;
> }
>
> void f_test()
> {
> auto sb=f();
> sb[2]=100; // I expected an "invalid access" (it points to
> "sa", a local variable)
> }
>
> However calling f_test seems ok and valgrind tool does not
> complain...
>
> So my questions are:
> 0/ does I miss something? (in C++ for sure you create a
> dangling pointer)
> 1/ what is the internal mechanism for that? Is the GC involved?
> Performance impact?
> 2/ any link describing this in more details is welcome
>
You *have* created a dangling pointer. It's just that for such a
simple little program, the part of the stack where the original
array was allocated isn't stomped at the point where you access
it after the function call. The same sort of program will also
work in C, where it's not uncommon for functions to return string
literals that are immediately printed to stdout or a log file.
One difference from C in this case is that it's still possible to
make things work even after the stack has been stomped and the
memory is no longer valid simply by increasing the length of the
returned slice: sb ~= 0, or perhaps sb.length+=n. This will cause
an allocation and sb will then own the memory block to which it
points.
Bear in mind that static arrays are implicitly sliced when passed
to or returned from a function anywhere a dynamic array is
expected. If you modify f() to look like this:
int[] f()
{
int[10] sa;
foreach(int i, ref sa_i;sa){
sa_i=i;
}
return sa;
}
You will now get an error about an escaping reference.
If you haven't read it already, I suggest taking a look at
Steven's array article [1]. I also answer these questions in
Chapter 2 of Learning D [2], and I'm pretty sure Ali talks about
it somewhere in 'Programming in D' [3].
[1] https://dlang.org/d-array-article.html
[2] https://www.packtpub.com/application-development/learning-d
[3] http://ddili.org/ders/d.en/index.html
More information about the Digitalmars-d-learn
mailing list