I have an XNA 3.0 project that compiled just fine in VS2008, but that gives compile errors in VS2010 (with XNA 4.0 CTP). The error:
Cannot use fixed local 'depthPtr' inside an anonymous method, lambda expression, or query expression
depthPtr
is a fixed float*
into an array, that is used inside a Parallel.For
lambda expression from System.Threading
. As I said, this compiled and ran just fine on VS2008, but it does not on VS2010, even when targeting .NET 3.5.
Has this changed in .NET 4.0, and even so, shouldn't it still compile when I choose .NET 3.5 as the target framework? Searching for the term "Cannot use fixed local" yields exactly one (useless) result, both in Google and Bing.
If this has changed, what is the reason for this? I can imagine capturing a fixed
pointer-type in a closure could get a bit weird, is that why? So I'm guessing this is bad practice? And before anyone asks: no, the use of pointers is not absolutely critical here. I would still like to know though :)
EDIT: As requested, a code sample (not from my program, obviously) that reproduces the error:
static unsafe void Main(string[] args)
{
float[] array = new float[10];
fixed (float* ptr = array)
{
Parallel.For(0, 10, i =>
{
ptr[i] = i;
});
}
}
The above compiles in VS2008 (well, aside from the reference to Parallel
, but any other lambda expression will do), but does not in VS2010.
fixed pins a pointer for the duration of the block. If you were to store the delegate to invoke later after the block had been exited the garbage collector could move the object between when the lambda is created and when the lambda is invoked. As to why targeting a different framework doesn't help, this is because this is being enforced by the language/compiler, not the runtime (if it were the runtime, it would be reported via an exception or similar at runtime, not by the compiler at compile time).
This works. Basically we eliminated the lambda containing an unsafe pointer and replaced it with a delegate to an instance of a class declared inside the fixed
block.
static unsafe void UnsafeTest(string[] args) {
float[] array = new float[10];
fixed(float* ptr = array) {
UnsafeOps ops = new UnsafeOps();
ops.p = ptr;
Parallel.For(0, 10, ops.Lambda);
}
}
unsafe class UnsafeOps {
public float* p;
public unsafe void Lambda(int value) {
p[value] = value;
}
}
Looks to me like .NET 4 added some half-arsed attempt at disallowing fixed memory access in the compiler. In the above code block you could define UnsafeOps
outside the fixed
block and access the array after the fixed
block. So it's not perfect...
The doco say you are not allowed to access unsafe code in an anonymous methods, and the same restrictions apply to lambdas, so I think that may be your problem. Do you have the actual compiler error no?
The compiler is correct to reject that code. Fixed can only be used on local variables, and variables captured by a closure are not local variables, they are hoisted into the class used to maintain state for the closure.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With