smart pointer for interior pointers

Steven Schveighoffer via Digitalmars-d digitalmars-d at puremagic.com
Wed May 27 16:31:32 PDT 2015


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:

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.

It has some advantages:

1. It can be defined at compile/initialization time:
struct S
{
    int x;
    SPtr!int y = SPtr(offsetFromytox); // not sure of an easy way to 
autocreate the offset :)
}

2. You can copy S anywhere, and every instance's y will point at the 
instance's x, without running any fixup code. You can even use memcpy.

The disadvantage, and I think there's only one, is that using SPtr must 
perform math that a straight pointer will not. I think in cases where 
this is needed, I prefer this disadvantage over the ones of other choices.

Thoughts? Does this seem like a good candidate for std.typecons?

If so, what's a good name? I want something kind of short :)

-Steve


More information about the Digitalmars-d mailing list