2013-05-14 2 views
4

나는 현재 C++ 함수 포인터에 C#을 대리자를 마샬링하기 위해 노력하고있어 나는이 example from Microsoft 바라 보았다 :가방지 위임

// MarshalDelegate1.cpp 
// compile with: /clr 
#include <iostream> 

using namespace System; 
using namespace System::Runtime::InteropServices; 

#pragma unmanaged 

// Declare an unmanaged function type that takes two int arguments 
// Note the use of __stdcall for compatibility with managed code 
typedef int (__stdcall *ANSWERCB)(int, int); 

int TakesCallback(ANSWERCB fp, int n, int m) { 
    printf_s("[unmanaged] got callback address, calling it...\n"); 
    return fp(n, m); 
} 

#pragma managed 

public delegate int GetTheAnswerDelegate(int, int); 

int GetNumber(int n, int m) { 
    Console::WriteLine("[managed] callback!"); 
    return n + m; 
} 

int main() { 
    GetTheAnswerDelegate^ fp = gcnew GetTheAnswerDelegate(GetNumber); 
    GCHandle gch = GCHandle::Alloc(fp); 
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(fp); 
    ANSWERCB cb = static_cast<ANSWERCB>(ip.ToPointer()); 
    Console::WriteLine("[managed] sending delegate as callback..."); 

// force garbage collection cycle to prove 
// that the delegate doesn't get disposed 
    GC::Collect(); 

    int answer = TakesCallback(cb, 243, 257); 

// release reference to delegate 
    gch.Free(); 
} 

호출 GCHandle 에 :: ALLOC() 가비지 수집기가 대리인을 수집하지 못하게해야합니다. 하지만 변수가 GetTheAnswerDelegate^fp은 이미 루트 객체이며 GCHandle에 대한 호출을 제거하더라도 충분히 위임을 유지합니다. 예제는 여전히 작동합니다. 다음과 같이 위임 인스턴스를 인라인 할 때만 :

IntPtr ip = Marshal::GetFunctionPointerForDelegate(gcnew GetTheAnswerDelegate(GetNumber)); 

나는 충돌이 표시됩니다.

Microsoft의 예가 잘못 되었나요?

답변

7

로컬 변수 수명 동안 디버거를 사용하면 효과가 사라집니다. 디버거가 연결되면 지터는 메소드가 끝날 때까지 사용중인 변수를 표시합니다. 디버깅을 신뢰성있게 만드는 것이 중요합니다. 그러나이 또한 GC.Collect() 호출에서 대리자 개체를 수집하지 못하게합니다.

디버거없이 프로그램의 릴리스 빌드를 실행하면이 코드가 충돌합니다. 디버그의 영향에

심층 대답은 가비지 컬렉터에 동작을 구축하는 것은 'ALLOC'호출을 수집에서 GC를 방지 대리자에 대한 참조를 추가 this post

+0

정말 옳았습니다! 릴리스 빌드 (GCHandle :: Alloc()없이)를 실행하면 디버거에서도 항상 오류가 발생합니다. 감사! – BugSlayer

1

에서 사용할 수 있습니다. 함수 포인터를 사용하여 완료되면 Alloc에서 반환 된 핸들을 유지하고 Free()를 호출해야합니다. 대리인은 Alloc 호출없이 GC'ed됩니다. GCHandle에서 Free()를 호출하지 않으면 프로그램이 누출됩니다. 디버거에서 실행할 때 메모리 환경이 약간 다릅니다. 의미가 있습니까?