Thread overview
"Error: address of variable this assigned to this with longer lifetime"
Mar 13, 2018
Nathan S.
Mar 13, 2018
ag0aep6g
Mar 13, 2018
Nathan S.
Mar 13, 2018
Jonathan M Davis
Mar 14, 2018
Nathan S.
Mar 14, 2018
Jonathan M Davis
March 13, 2018
What is this malarky?

https://run.dlang.io/is/S42EBb

"onlineapp.d(16): Error: address of variable this assigned to this with longer lifetime"

```d
import std.stdio;

struct SmallString
{
    char[24] small;
    char[] data;

    @disable this();

    this(scope const(char)[] s) @safe
    {
        if (s.length < small.length)
        {
            small[0 .. s.length] = s[];
            small[s.length] = 0;
            data = small[0 .. s.length];
        }
        else
        {
            assert(0, "Compilation failed before I wrote this.");
        }
    }
}

void main()
{
    writeln("Hello D");
}
```
March 13, 2018
On Tuesday, 13 March 2018 at 20:49:16 UTC, Nathan S. wrote:
> "onlineapp.d(16): Error: address of variable this assigned to this with longer lifetime"
>
> ```d
[...]
> struct SmallString
> {
>     char[24] small;
>     char[] data;
[...]
>     this(scope const(char)[] s) @safe
>     {
[...]
>             data = small[0 .. s.length];
[...]
>     }
> }
[...]
> ```

You're storing a reference to `small` in `data`. When a SmallString is copied, that reference will still point to the original `small`. When the original goes out of scope, the reference becomes invalid, a dangling pointer. Can't have those in @safe code.

The error message isn't exactly clear, though.
March 13, 2018
On Tuesday, 13 March 2018 at 21:07:33 UTC, ag0aep6g wrote:
> You're storing a reference to `small` in `data`. When a SmallString is copied, that reference will still point to the original `small`. When the original goes out of scope, the reference becomes invalid, a dangling pointer. Can't have those in @safe code.
>
> The error message isn't exactly clear, though.

The error does not go away when restoring these lines:

```
    @disable this(this);
    @disable void opAssign(this);
```
March 13, 2018
On Tuesday, March 13, 2018 21:35:50 Nathan S. via Digitalmars-d-learn wrote:
> On Tuesday, 13 March 2018 at 21:07:33 UTC, ag0aep6g wrote:
> > You're storing a reference to `small` in `data`. When a SmallString is copied, that reference will still point to the original `small`. When the original goes out of scope, the reference becomes invalid, a dangling pointer. Can't have those in @safe code.
> >
> > The error message isn't exactly clear, though.
>
> The error does not go away when restoring these lines:
>
> ```
>      @disable this(this);
>      @disable void opAssign(this);
> ```

And you can't get rid of it, because the object can still be moved, which would invalidate the pointer that you have referring to the static array. As it stands, it simply does not work in D to have pointers (or dynamic arrays which refer to) member variables of structs. With the use of scope and DIP 1000, they can work within restricted circumstances, but pretty much anything that extends beyond a function call is going to have @safety problems. To fix the problem, D would either need to provide a way to make it illegal for a struct to be moved (which could cause a number of problems), or it would have to provide hooks so that it would be possible to do stuff like adjust pointers when an object is moved. There's a recent discussion the problem here:

https://issues.dlang.org/show_bug.cgi?id=17448

- Jonathan M Davis

March 14, 2018
On Tuesday, 13 March 2018 at 22:33:56 UTC, Jonathan M Davis wrote:
> And you can't get rid of it, because the object can still be moved, which would invalidate the pointer that you have referring to the static array.
> ...
> https://issues.dlang.org/show_bug.cgi?id=17448

Thanks for the info.
March 14, 2018
On Wednesday, March 14, 2018 07:11:49 Nathan S. via Digitalmars-d-learn wrote:
> On Tuesday, 13 March 2018 at 22:33:56 UTC, Jonathan M Davis wrote:
> > And you can't get rid of it, because the object can still be
> > moved, which would invalidate the pointer that you have
> > referring to the static array.
> > ...
> > https://issues.dlang.org/show_bug.cgi?id=17448
>
> Thanks for the info.

Another way to tackle this problem is to not slice the static array but to keep track of either two indices or an index and the length explicitly and then use those with the static array. It's more annoying in some respects, but it solves the @safety problem.

LOL. It was actually thanks to your post here that it clicked for me that I had this problem with some of my recent code. I was well aware of the problems with having pointers to structs on the stack, but it hadn't clicked that slicing a static array like that was the same thing until you posted about it. I had realized that having a dynamic array in the struct being a slice of a static array in the struct would cause problems when the struct was copied, and I'd dealt with that with a postblit constructor, but the issue with moving didn't click until I connected the dots between your post and that recent bugzilla issue. So, answering your question actually helped me catch a bug in my code.

- Jonathan M Davis