C#指针和值类型变量的重定位

时间:2016-07-24 10:57:41

标签: c# .net visual-studio-2015 unsafe

我编写了以下不安全的类,它包装了一个指向int的指针:

unsafe class PtrWrapper
{
   public PtrWrapper(ref int val)
   {
       fixed (int* ptr = &val)
       {
           m_ptr = ptr;
       }
   }
   public int Value
   {
       get { return *m_ptr; }
       set { *m_ptr = value; }
   }
   int * m_ptr;
}

我已经对它进行了测试,似乎工作正常,但是我只是再次阅读了reference,看起来指针上的所有操作都应该在语句中完成:

  

如果没有修复,指向可移动托管变量的指针就是   垃圾收集可以重新定位变量   不可预知的。

那么,当我调用Value属性时,是否有可能指针被重新定位在内存中,而我的指针指向其他东西?我知道如果指针超出范围,我会遇到问题,但我会按照我如何使用我的课来解释它。所以我要求重新定位一个已超出范围的值类型变量。

1 个答案:

答案 0 :(得分:3)

是的,这很有可能,甚至可能。

在堆上:

class M 
{
    public int i;
    public PtrWrapper w;

    public M()
    {
        i = 42;
        w = new PtrWrapper(ref i);
    }
}

var m = new M();
var value = m.w.Value; // probably 42

// move m to gen 2
GC.Collect();
GC.Collect();

value = m.w.Value; // probably a random value

这就是为什么它被称为不安全 :) fixed只会阻止某些东西在范围内移动。

在堆栈上但它应该没问题。只有当你超出范围时,才会弹出堆栈上的变量,例如:

PtrWrapper M()
{
    var i = 42;
    var w = new PtrWrapper(ref i);
    return w;
}

var w = M();
var value = w.Value; // some random value

请注意,捕获的变量(在lambdas中)实际上是在堆上,所以你应该小心那个场景中的那些。