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