|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionOne very confusing facet of the now obsolete Managed Extensions to C++ was
its pointer usage syntax, where What are interior pointers?Interior pointers are essentially pointers into the CLI heap (needn't
always point to the CLI heap though) that point to managed objects or
members of managed objects. The basic problem with using a native pointer to
point to a managed object or a member-object of a managed object is that the
Garbage Collector might move the object around in the CLI heap during a
GC/Memory-Compaction cycle. Thus, a managed object at That's where interior pointers come into play. The CLR knows about interior pointers and every time the Garbage Collector relocates an object pointed to by an interior pointer variable, the CLR automatically updates the value of the interior pointer to reflect the new location. So we can continue using the interior pointer and yet be totally oblivious as to the GC moving our pointed-to object around the CLI heap. Here's some code to see this in action :- Here's our test class with an ref class Test
{
public:
int m_i;
};
Here's a function to try and fill up the CLI heap's Generation-0 memory. [You might have to modify the loop-count (10,000 for me) to other values if you are not getting the desired effect] void DoLotsOfAllocs()
{
for(int i=0; i<10000; i++)
{
gcnew Test();
}
}
Here's the test code. void _tmain()
{
DoLotsOfAllocs();
Test^ t = gcnew Test();
t->m_i = 99;
interior_ptr<int> p = &t->m_i;
printf("%p %d\r\n",p,*p);
DoLotsOfAllocs();
printf("%p %d\r\n",p,*p);
Output on my machine [addresses will be different for you] ******* Output ******
00AC9B3C 99
00AA8D18 99
There you go; the same interior pointer variable Passing by reference using interior pointersOne handy use for interior pointers is when you have a requirement for functions with pass-by-ref arguments. Let's take a simple function that simply squares the passed integer :- ref class Test
{
public:
int m_i;
};
void Square(interior_ptr<int> pNum)
{
*pNum *= *pNum;
}
Now see this code. void _tmain()
{
Test^ t = gcnew Test();
t->m_i = 99;
interior_ptr<int> p = &t->m_i;
printf("%d\r\n",*p);
Square(p);
printf("%d\r\n",*p);
int a = 10;
Square(&a);
printf("%d\r\n",a);
Output :- ******* Output ******
99
9801
100
You can see how we can pass both interior pointers as well as native pointers to the same function; this is because native pointers automatically convert to interior pointers. [Note that interior pointers cannot convert to native pointers] Now that we've seen how interior pointers can be used for passing values by reference, it should be stated here that the same could be just as easily accomplished using tracking references. See below another function that does the same thing using a tracking reference as parameter. void Square2(int% pNum)
{
pNum *= pNum;
}
And the corresponding caller code. void _tmain()
{
Test^ t = gcnew Test();
t->m_i = 99;
printf("%d\r\n",t->m_i);
Square2(t->m_i);
printf("%d\r\n",t->m_i);
int a = 10;
Square2(a);
printf("%d\r\n",a);
Tracking references and interior pointers are quite similar in nature, though you can do a lot more with interior pointers like pointer arithmetic and pointer comparison. Pointer arithmetic with interior pointersHere's some sample code that iterates through and sums an array of void ArrayStuff()
{
array<int>^ arr = gcnew array<int> {2,4,6,8,3,5,7};
interior_ptr<int> p = &arr[0];
int s = 0;
while(p != &arr[0] + arr->Length)
{
s += *p;
p++;
}
printf("Sum = %d\r\n",s);
}
And here's some code that directly manipulates a String^ str = "hello";
interior_ptr<Char> ptxt = const_cast< interior_ptr<Char> >(
PtrToStringChars(str));
for(int i=0; i<str->Length; i++)
*(ptxt+i) = *(ptxt+i) + 1;
Console::WriteLine(str);
If you are of a masochistic disposition, you could change the for(; (*ptxt++)++; *ptxt);
with the same results. It doesn't produce very legible looking code but it
does demonstrate that you can do pointer comparison (implicit check for Points of interestYou cannot have an interior pointer as a member of a class and I guess this is to maintain language interoperability. I mean you can't have VBers using your class if it's full of interior pointer member objects, can you? (If I guessed wrong, please feel free to correct me) You cannot use an interior pointer to point to a All interior pointers are implicitly initialized to The compiler will emit a For value class V
{
void A()
{
interior_ptr<V> pV1 = this;
V* pV2 = this; //won't compile
}
};
ConclusionI hope I've given a pretty decent coverage of interior pointers and their usage in C++/CLI. Kindly submit your feedback so that I get a chance to improve on this article. Thank you.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||