C#指针和值类型变量的重新定位
本文关键字:新定位 定位 指针 类型变量 | 更新日期: 2023-09-27 17:58:19
我已经编写了以下不安全的类,它封装了指向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;
}
我已经测试过了,它似乎工作得很好,但我刚刚再次阅读了fixed上的引用,看起来指针上的所有操作都应该在语句中完成:
如果没有固定,指向可移动托管变量的指针将为没有什么用处,因为垃圾回收可以重新定位变量不可预测。
那么,当我调用Value属性时,指针对象是否可能在内存中重新定位,而我的指针指向其他对象?我知道,如果指针对象超出范围,我会遇到问题,但我会通过如何使用我的类来解释。所以我问的是,重新定位一个值类型变量,该变量的尚未超出范围。
是的,这很有可能,甚至很有可能。
堆上:
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
for (int i = 0; i < 10; i++)
{
GC.Collect();
}
Debug.Assert(GC.GetGeneration(m) == 2);
value = m.w.Value; // probably a random value or AccessViolationException
这就是为什么它被称为不安全。fixed
只阻止某个对象在范围内移动。
然而,在堆栈上应该是好的。只有当您超出范围时,堆栈上的变量才会弹出,例如在本例中:
PtrWrapper M()
{
var i = 42;
var w = new PtrWrapper(ref i);
return w;
}
var w = M();
Console.WriteLine(); // do something else on the stack
var value = w.Value; // some random value
请注意,捕获的变量(在lambdas中)确实在堆中,因此在该场景中应该小心处理这些变量。