__pin

Note   This topic applies only to version 1 of Managed Extensions for C++. This syntax should only be used to maintain version 1 code. See pin_ptr for information on using the equivalent functionality in the new syntax.

Prevents an object or embedded object of a managed class from being moved by the common language runtime during garbage collection.

__pin identifier

Remarks

The __pin keyword declares a pointer to an object or embedded object of a managed class and prevents that object from being moved during garbage collection by the common language runtime. This is useful when passing the address of a managed class to an unmanaged function because the address will not change unexpectedly during resolution of the unmanaged function call.

A pinning pointer remains valid in its lexical scope. As soon as the pinning pointer goes out of scope, the object is no longer considered pinned (unless, of course, there exist other pinning pointers pointing to or into the object).

The MSIL has no concept of "block scope" -- all local variables live in the scope of the function. To let the system know the pinning is no longer in effect, the compiler generates code that assigns NULL to the pinning pointer. This is also what you can do yourself, if you need to unpin the object without leaving the block.

You should not convert your pinning pointer to an unmanaged pointer and continue using this unmanaged pointer after the object is no longer pinned (after the pinning pointer goes out of scope). Unlike gc pointers, pinning pointers can be converted to nogc, unmanaged pointers. However, it is user's responsibility to maintain the pinning while the unmanaged pointer is in use.

Using a pinned pointer to get the address of a variable and then using that address after the pinning pointer goes out of scope, should not be done.

// keyword_pin_scope_bad.cpp
// compile with: /clr:oldSyntax /LD
#using <mscorlib.dll>
__gc struct X {
   int x;
};
 
int* Get_x( X* pX ) {
   int __pin* px = &pX -> x;
   return px;   // BE CAREFUL px goes of scope, 
                // so object pointed by it is no longer pinned,
                // making the return value unsafe.
}

The following sample shows correct behavior:

// keyword_pin_scope_good.cpp
// compile with: /clr:oldSyntax /LD
#using <mscorlib.dll>
__gc struct X {
   int x;
};
 
int Get_x( X* pX ) {
   int __pin* px = &pX -> x;
   return *px;   // OK, value obtained from px before px out of scope
}

Example

In the following example, the object pointed to by pG is pinned until it passes out of scope:

// keyword__pin.cpp
// compile with: /clr:oldSyntax
#using <mscorlib.dll>
#include <iostream>

__gc class G { 
public: 
   int i; 
   G() {i = 0;};
};

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

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

Output

1