Export (0) Print
Expand All

7.7 Pinning Pointers

Visual Studio .NET 2003

An object or sub-object of a managed class can be pinned, in which case the common language runtime will not move it during garbage collection. The principal use of this is to pass a pointer to managed data as an actual parameter of an unmanaged function call.

A local variable called a pinning pointer can be declared whose top-level pointer type is qualified by the __pin keyword. During a collection cycle, the runtime will inspect the metadata created for the pinning pointer and will not move the item it points to.

Example

// __gc_pointer16.cpp
// compile with: /clr /EHsc
#using <mscorlib.dll>
#include <iostream>
__gc class G {
public:
   int i; 
   G() { i = 0; };
};

class H {
public:
   void incr(int * i) {   // unmanaged function
      (*i)++;
      std::cout << *i << std::endl;
   };
};

int main() {
   G __pin * pG = new G;   // pG is a pinning pointer
   H * h = new H;
   h->incr(& pG -> i);   // pointer to managed data passed as actual
                         // parameter of unmanaged function call
}

Output

1

A pinned object is pinned only while a pinning pointer points to it. It is no longer pinned when its pinning pointer goes out of scope, or is set to 0 in the program. After that, any unmanaged pointers that remain pointing to that object must not be dereferenced. An unpinned item can be moved in the heap by the garbage collector. Any __nogc pointers that still point to it will not be updated, and dereferencing one of them could raise an unrecoverable exception.

Example

// __gc_pointer17.cpp
// compile with: /clr /LD
#using <mscorlib.dll>
__gc class G {
public:
   int i;
};

void f(G * pG) {
   G __pin* ppG = pG;   
   // the object pointed to by pG is pinned until the pinning 
   // variable ppG goes out of scope,
   ppG = 0;   // or is set to 0
}

A pinning pointer is volatile by default. It is redundant but not an error if the user declares a pinning pointer to be volatile. This prevents the optimizer from deleting an assignment of 0 to a pinning pointer in the source code, even though the assignment appears to be dead code.

Pinning a sub-object defined in a managed object has the effect of pinning the entire object. For example, if any element of an array is pinned, then the whole array is also pinned. There are no extensions to the language for declaring a pinned array. To pin an array, declare a pinning pointer to its element type, and pin one of its elements.

Example

// __gc_pointer18.cpp
// compile with: /clr
#using <mscorlib.dll>
#include <stdio.h>
using namespace System;
int main() {
   Byte arr[] = new Byte[4]; // arr is a managed array
   arr[0] = 'C';
   arr[1] = '+';
   arr[2] = '+';
   arr[3] = '0';
   Byte __pin * p = &arr[1]; // entire array is now pinned
   unsigned char * cp = p;
   printf("%s\n", cp); // bytes pointed at by cp will not move during call
}

Output

++0

Characteristics

  • A pinning pointer can be implicitly converted to a __nogc pointer.

This is the only mechanism provided for passing addresses in the common language runtime heap to functions expecting __nogc pointers. The primary use for this is passing such addresses to unmanaged functions in external DLLs.

Constraints

  • A pinning variable shall be a nonstatic local variable.

Except for its pinning properties, a pinning pointer is identical to a __gc pointer.

  • Two function overloads shall not differ only by the use of pin and __gc pointer types.
  • A pinning pointer type shall not be used in a cast expression. It can only be used to declare a variable.

    Example

    // __gc_pointer19.cpp
    // compile with: /clr
    #using <mscorlib.dll>
    using namespace System;
    __gc struct G { int i; };
    
    int main() {
       Object  *o = new G;
       if ( G __pin *pG = dynamic_cast<G __pin *>(o) ) {   // C3834
          pG->i = 10;
       }
    }
    
  • A pinning pointer can be implicitly converted to a __gc pointer.

    Example

    // __gc_pointer20.cpp
    // compile with: /clr /LD
    #using <mscorlib.dll>
    __gc class G {
    public:
       int i;
    };
    
    void f(G * pG) {
       G __pin * ppG = pG;
       G * pG2 = ppG;   // ok
    };
    
  • A __nogc pointer can be converted to a pinning pointer only if the pinning pointer is an interior __gc pointer.

    Example

    // __gc_pointer21.cpp
    // compile with: /clr
    #using <mscorlib.dll>
    struct G { int i; };
    __gc struct H { int j; };
    int main() {
       G * g = new G;   // g is a __nogc whole object pointer
       H * h = new H;
       int __pin * k = & h -> j;   // k is a pinning interior __gc pointer
       int * l = & g -> i;   // l is a __nogc pointer
       k = l; // ok
    };
    
Show:
© 2015 Microsoft