Search code examples
c++-clipin-ptr

C++/CLI pin_ptr's usage in proper way


I am newbie of C++/CLI.
I already know that the pin_ptr's functionality is making GC not to learn to specified object.

now let me show you msdn's example.
https://msdn.microsoft.com/en-us//library/1dz8byfh.aspx

// pin_ptr_1.cpp  
// compile with: /clr   
using namespace System;  
#define SIZE 10  

#pragma unmanaged  
// native function that initializes an array  
void native_function(int* p) {  
   for(int i = 0 ; i < 10 ; i++)  
    p[i] = i;  
}  
#pragma managed  

public ref class A {  
private:  
   array<int>^ arr;   // CLR integer array  

public:  
   A() {  
      arr = gcnew array<int>(SIZE);  
   }  

   void load() {  
     pin_ptr<int> p = &arr[0];   // pin pointer to first element in arr  
     int* np = p;   // pointer to the first element in arr  
     native_function(np);   // pass pointer to native function  
   }  

   int sum() {  
      int total = 0;  
      for (int i = 0 ; i < SIZE ; i++)  
         total += arr[i];  
      return total;  
   }  
};  

int main() {  
   A^ a = gcnew A;  
   a->load();   // initialize managed array using the native function  
   Console::WriteLine(a->sum());  
}  

hear is the question.

Isn't it okay, the passed object(arr) not pinned ? because the unmanaged code(native_function) is sync operation and finished before the C++/CLI code (load)

is there any chance the gc destory arr, even though the main logic is running? (I think A is main's stack variable and arr is A's member variable, so while running main, it should visible)

if so, how can we guarantee that the A is there before invoking load?
(only while not running in native-code?)

int main() {
  A^ a = gcnew A; 
  // I Think A or arr can be destroyed in here, if it is able to be destroyed in native_function. 
  a->load();  
  ...
}

Thanks, in advance.


Solution

  • The problem that is solved by pinning a pointer is not a normal concurrency issue. It might be true that no other thread will preempt the execution of your native function. However, you have to count in the garbage collector, which might kick in whenever the .NET runtime sees fit. For instance, the system might run low on memory, so the runtime decides to collect disposed objects. This might happen while your native function executes, and the garbage collector might relocate the array it is using, so the pointer you passed in isn't valid anymore.

    The golden rule of thumb is to pin ALL array pointers and ALL string pointers before passing them to a native function. ALWAYS. Don't think about it, just do it as a rule. Your code might work fine for a long time without pinning, but one day bad luck will strike you just when it's most annoying.