tags:

views:

78

answers:

2

What happens in memory when we pass a value type - which has been stored on the stack - by reference?

A temp value/pointer must be created somewhere to change the origninal value when the method completes. Could someone please explain or point me to the answer - lots of stuff on memory but none seem to answer this. ty

A: 

It sounds like you're looking for some details on Boxing and Unboxing, which are the terms used to describe treating a value type as a reference type.

There's lots of articles out there that describe the process, I'll try to find some decent ones--but here's one for starters.

STW
Here's an answer to "why is boxing and unboxing bad?" which provides some insight into the pointer handling and performance hit of boxing/unboxing value types: http://stackoverflow.com/questions/13055/what-is-boxing-and-unboxing-and-why-is-it-bad/25324#25324
STW
+3  A: 

If you have a method like this:

static void Increment(ref int value)
{
   value = value + 1;
}

and call it like this:

int value = 5;
Increment(ref value);

then what happens is that, instead of the value 5 being pushed on the stack, the location of the variable value is pushed on the stack. I.e. the contents of value are changed directly by Increment and not after the method completes.

Here's the IL of the method and the method call respectively:

.method private hidebysig static void Increment(int32& 'value') cil managed
{
    .maxstack 8
    L_0000: nop 
    L_0001: ldarg.0 
    L_0002: ldarg.0 
    L_0003: ldind.i4         // loads the value at the location of 'value'
    L_0004: ldc.i4.1 
    L_0005: add 
    L_0006: stind.i4         // stores the result at the location of 'value'
    L_0007: ret 
}

.method private hidebysig static void Main() cil managed
{
    .entrypoint
    .maxstack 9
    .locals init ([0] int32 value) //   <-- only one variable declared
    L_0000: nop 
    L_0001: ldc.i4.5
    L_0002: stloc.0 
    L_0003: ldloca.s 'value'   // call Increment with the location of 'value'
    L_0005: call void Program::Increment(int32&)
    L_000a: ret 
}
dtb
Thanks - So a pointer is create on the stack to values' location on the stack... cool! I wish the call stack would show exactly what is going on in memory. Should probably get a myself a memory profiler.
If you're interested in what's going on behind the scenes it's always worth having a look at the IL generated by the compiler. You can use .NET Reflector to disassemble your assemblies.
dtb
I do use reflector often but don't fully understand IL call just yet. I must admit I didn't think to check the IL here for some reason... Thanks again.