[Dlang-internal] Strange behavior when appending pointers of structs to arrays
Mike Parker
aldacron at gmail.com
Sun Feb 4 05:41:04 UTC 2018
For starters, this sort of question belongs in the Learn forum.
Now to your problem.
> The resulting executable returns the following outputs:
>
> C:\Users\Jonathan\Desktop\bug>dmd .\bug.d -version=bad1
>
> C:\Users\Jonathan\Desktop\bug>bug.exe
> children: 1
> grandchildren: 4203068
Running at run.dlang.io:
children: 1
grandchildren: 10
>
> C:\Users\Jonathan\Desktop\bug>dmd .\bug.d -version=bad2
>
> C:\Users\Jonathan\Desktop\bug>bug.exe
> children: 1
> grandchildren: 1
children: 1
grandchildren: 140722524752048
>
> Why?
Because structs are value types and you're creating them on the
stack. Anything created on the stack in a function will
eventually be stomped after the function exits, but with structs
you also have the fact that the instance is destroyed. You can
see this by adding a destructor to your Foo type and sprinkling
some writelns around:
======
import std.stdio : writeln;
struct Foo
{
Foo*[] children;
~this() { writeln("Destroyed!"); }
void value()
{
writeln("Entered value.");
Foo bar = Foo();
version (bad1)
{
this.children ~= &bar;
}
version (bad2)
{
this.children.length += 1u;
this.children[$-1] = &bar;
}
writeln("Exiting 'value'");
}
void bark()
{
writeln("children: ", this.children.length);
writeln("grandchildren: ",
this.children[0].children.length);
}
}
void main ()
{
Foo foo = Foo();
version (good)
{
Foo bar = Foo();
foo.children ~= &bar;
}
else
{
writeln("Entering value.");
foo.value();
writeln("value exited.");
}
foo.bark();
writeln("Exiting main");
}
=======
Running bad1 & bad2 will print something like this:
Entering value.
Entered value.
Exiting 'value'
Destroyed!
value exited.
children: 1
grandchildren: 10
Exiting main
Destroyed!
As you can see, the Foo instance created inside value will be
destroyed when the function exits, so that by the time you call
foo.bark, children[0] is no longer in a valid state -- hence the
garbage value for children[0].children.length. If you want bar to
persist outside of value, you need to allocate it on the heap:
Foo* bar = new Foo;
this.children ~= bar;
More information about the Dlang-internal
mailing list