tags:

views:

481

answers:

4

I know I'm not asking this quite right, either. Please help me better form my question.

I'm having a bit of a hard time getting my mind wrapped around handles -- in some ways, it looks like pointers. But unlike pointers, it seems like I can assign values directly to the handle variable, and it affects the underlying data value, not the handle itself.

The test code clearly shows that I get the same value whether I use the handle, or if I "dereference" the handle to get to the data. Clearly, this wouldn't work with unmanaged pointers. What am I not understanding?

#include <iostream>

int main()
{

  int ^y;
  int ^a, ^b, ^c;
  long x;

   y= gcnew int(100);
   a=y;
   b=y;
   c=y;

   c= gcnew int(200);
   b= 300;

   System::Console::WriteLine(y); // returns 100 (instead of something pointer-like)
   System::Console::WriteLine(*y); // also returns 100

   System::Console::WriteLine(a); // 100
   System::Console::WriteLine(b); // 300
   System::Console::WriteLine(c); // 200 

   x = static_cast<long>(y);
   *y = 10;

   System::Console::WriteLine(x); // 10
   System::Console::WriteLine(y); // 10
   System::Console::WriteLine(*y); // 10

  }

Edit to add -- I suspected that WirteLine might have done the dereferencing for me, but I would have expected the static cast to long would not. Is this related to autounboxing as welll?

+2  A: 

Side effect of using WriteLine.

just 'y' is being treated like an 'object reference' and probably being interrogated for IFormattable, and then having ToString() called on it. '*y' is passing an int.

To test this, make another function call Foo(int ^) and see what you are allowed to pass in, and then change it to 'Foo(int)'.

I think you are just getting fooled by the 'varargs' nature of WriteLine.

Joe
A: 

Don't rely on WriteLine to tell you what *y and y are, run it from the debugger and inspect *y and y yourself to see the difference.

hhafez
+2  A: 

It's a bit sad that C++/CLI allows this syntax. The int type is a value type, the hat is used for reference types. Your "y" variable does not store an int, it stores System::Object. The compiler automatically generates a boxing instruction when you assign it. Console::WriteLine() has otherwise no problem displaying the value of an object that's a boxed int.

The rule of thumb: use the hat when it is a class object, omit it for simple value types. Avoid the stack semantics of a reference type (omitting the hat so it automatically calls the destructor when the scope ends) until you really grok the difference between value and reference types and why Dispose() is important.

Hans Passant
A: 

Think of handles to value types as being like a smart handle you might have written yourself, which has operator overloading for conversions. That way, using the handle where you can supply an int would work (via the conversion operator) as well as dereferencing the handle to get the int contained in the object.

With regards to Writeline, I think of it as being like the stream output operators where many conversions are implicitly invoked. Just as you might safely go cout << y, you can write System::Console::WriteLine(y).

Andy Dent