smart pointer for interior pointers

Artur Skawina via Digitalmars-d digitalmars-d at puremagic.com
Wed May 27 17:21:35 PDT 2015


On 05/28/15 01:31, Steven Schveighoffer via Digitalmars-d wrote:
> I just was working on a project, and I had a need for two members of a struct to share state.
> 
> How could this work? A simple example:
> 
> struct S
> {
>    int x;
>    int *y; // should refer to x
>    this(int v)
>    {
>       x = v;
>       y = &x;
>    }
> }
> 
> But this doesn't work on copying, because when you copy S, S.y is still pointing at the OLD S. Example:
> 
> 
> S s1 = S(5);
> S s2 = s1;
> s1.x = 4;
> writeln(*s2.y); // oops, writes 4, because s2.y is pointing at s1.x, not s2.x
> 
> But we can solve this with a postblit:
> 
> this(this) { y = &x;}
> 
> Although this works, there are issues:

It doesn't.

   S f() { return S(42); }


> 1. y's target is defined by the type, it's impossible to rebind y at runtime, without having a copy mess that up.
> 2. Copying still requires executing a function to fixup the pointer.
> 3. Even if y's relative target isn't supposed to change, S has to know where to point y at relative to itself! For example, if S was inside a struct like this:
> 
> struct S2
> {
>    S s;
>    int y; // I really want s.x to point at *this* y
> }
> 
> Now, you need to add a postblit to S2 as well.
> 
> But with alias this, we can define a way to solve all these problems.
> 
> struct SPtr(T)
> {
>     ptrdiff_t _offset;
>     void opAssign(T *orig) { _offset = cast(void *)orig - cast(void *)&this;}
>     inout(T) *_get() inout { return cast(inout(T)*)((cast(inout(void) *)&this) + _offset);}
>     alias _get this;
> }
> 
> Basically, instead of storing the pointer, we store the offset to the struct itself. This works as long as the SPtr instance stays co-located with its target.

  auto a = s.y;
  // this 'a' now implicitly converts to 'int', but...

  void g(T)(T a);
  g(s.y);         // ditto.


artur


More information about the Digitalmars-d mailing list