Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting pointer to struct inside itself (unsafe context)

Long story short, I'll provide a simplistic example where it might be useful:

public struct Vector3f {
    public float x;
    public float y;
    public float z;

    public unsafe float this[int index] {
        get {
            // Get "p" somehow, so that it points to "this"...

            return p[index];
        }

        set {
            // Get "p" somehow, so that it points to "this"...

            p[index] = value;
        }
    }
}

I guess you got my point there:

var v = new Vector3f();

Assert(v.x == v[0]);

EDIT 1:

For those, who still ask :)

Assert(v.y == v[1]);
Assert(v.z == v[2]);

EDIT 2:

Does fixed create redundant overhead here? Or maybe this struct is already fixed, and therefore fixed has no effect here and is only needed to satisfy the compiler? Possible answer.

like image 472
Alexander Shukaev Avatar asked Jan 06 '12 12:01

Alexander Shukaev


2 Answers

First off, I would not use unsafe code for this unless I had first determined (1) that the obvious code with the switch would be the slowest code in the entire program and causing significant, user-observable slowdowns, and that (2) going to unsafe code fixes the performance problem.

Second, if I were to use unsafe code, it is extraordinarily dangerous to make assumptions about structure packing. The CLR is allowed broad lattitude in how it chooses to pack structures. If you are going to do this dangerous thing then you should use the struct layout attribute to ensure that the floats are exactly where you need them to be.

Third, what stops a buggy caller from passing a negative index, or a too-large index?

Fourth:

Does fixed create redundant overhead here?

I don't know what "redundant overhead" means. "fixed" makes the jitter tell the garbage collector "do not move this thing because I need to do pointer arithmetic on it". You are fixing for a short period, which is ideal; fixing for a long time makes it more likely that a collection will get messed up because the pinned storage could not be moved.

Fifth:

Or maybe this struct is already fixed, and therefore fixed has no effect here and is only needed to satisfy the compiler?

Maybe! Maybe the variable referred to by "this" is already a fixed variable. Maybe it isn't. How is the compiler supposed to know whether the "this" of the struct is a ref to fixed storage or not? We have to assume the worst, so you are required to fix it.

like image 163
Eric Lippert Avatar answered Oct 07 '22 02:10

Eric Lippert


You mean something like this?

get
{
    // (index validation omitted)
    fixed (Vector3f* thisPtr = &this)
    {
        return ((float*)thisPtr)[index];
    }
}
like image 20
ordag Avatar answered Oct 07 '22 01:10

ordag