Struct delegate access corruption

tsbockman thomas.bockman at gmail.com
Wed Feb 17 19:42:00 UTC 2021


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);
}



More information about the Digitalmars-d-learn mailing list