On Wednesday, 17 February 2021 at 17:45:01 UTC, H. S. Teoh wrote:
I.e., the following is NOT a good idea:

        struct S {
                void delegate() member;
                this() {
                        member = &this.impl;
                }
                private void impl();
        }

because a pointer to S is stored inside S itself, so as soon as S gets copied or moved, the delegate context pointer is no longer valid (or else points to a different copy of the struct than the one it will be called from).

A copy constructor and opAssign can be used to update pointers that are relative to &this:
    https://dlang.org/spec/struct.html#struct-copy-constructor

// The following program prints 9 with the copy constructor, or 7 if it is commented out:
module app;

import std.stdio;

struct Foo {
    int[2] things;
    private int* ptr;

this(const(int[2]) things...) inout pure @trusted nothrow @nogc {
        this.things = things;
        ptr = &(this.things[0]);
    }

    // Copy constructor:
this(scope ref const(typeof(this)) that) inout pure @trusted nothrow @nogc {
        this.things = that.things;
        this.ptr = this.things.ptr + (that.ptr - that.things.ptr);
    }
    // Defining a matching opAssign is a good idea, as well:
ref typeof(this) opAssign(scope ref const(typeof(this)) that) return pure @trusted nothrow @nogc {
        __ctor(that);
        return this;
    }

    void choose(const(int) x) pure @trusted nothrow @nogc {
        ptr = &(things[x]); }
@property ref inout(int) chosen() return inout pure @safe nothrow @nogc {
        return *ptr; }
}

void main() {
    auto foo = Foo(3, 7);
    foo.choose(1);

    Foo bar = foo;
    bar.things[1] = 9;
    writeln(bar.chosen);
}

Reply via email to