[Step. 05] 관리 코드의 array를 비관리 코드에 포인터로 전달

C++/CLI 2010. 7. 9. 08:30 Posted by 알 수 없는 사용자

아마 C++ 프로그래머가 C++/CLI를 사용할 때 가장 신경 쓰이는 부분이 관리 코드를 어떻게 하면 비관리 코드와 연동하는 방법이라고 생각합니다.

 

그래서 아직 C++/CLI의 델리게이트 등 C++/CLI의 특징을 설명하지 않은 것이 많지만 이런 것은 C#를 공부하면 배울 수 있는 것이므로 급하지 않다고 생각합니다. 그래서 관리 코드와 비 관리 코드의 연동에 대해서 앞으로 몇 차례에 걸쳐서 설명하려고 합니다.

 

이번은 첫 번째로 간단하게 array로 만든 배열을 비관리 코드의 포인터로 어떻게 전달하는지 설명하겠습니다.

 

먼저 코드를 봐 주세요^^

#include <Iostream>

 

using namespace System;

 

void DumpNativeArray( int* pArrNums, int length )

{

    for( int i=0; i<length; i++ )

    {

        std::cout << pArrNums[i] << std::endl;

    }

}

 

int main()

{

array< int >^ ArrNums = gcnew array<int>(3);

ArrNums[0] = 1;

ArrNums[1] = 2;

ArrNums[2] = 3;

 

     pin_ptr<int> pNative = &ArrNums[0];

     DumpNativeArray(pNative,ArrNums->Length);

     pNative = nullptr;

 

getchar();

     return 0;

}

 

위 코드의 핵심은

pin_ptr<int> pNative = &ArrNums[0];

입니다.

 

앞서 설명한 pin_ptr을 사용하였습니다. pin_ptr을 사용하여 관리 힙에 할당된 객체가 이동하지 못하도록 고정합니다. 고정하는 이유는 비관리 코드로 메모리 주소를 넘기기 때문에 관리 힙에서 이동이 되면 안되기 때문입니다.


또 여기서 자세히 봐야 되는 것이 있습니다.

pin_ptr<int> pNative = &ArrNums[0];


pNative&ArrNums이 아닌 &ArrNums[0]을 대입하였습니다. 이유는 관리 코드에서는 &ArrNums ArrNums의 요소가 아닌 ArrNums 오브젝트 자체를 가리키는 것이기 때문입니다.

&ArrNums[0]을 대입해야 ArrNums에 들어가 있는 요소의 첫 번째 주소를 비관리 코드에 주소를 넘길 수 있습니다.

 



제가 요즘 바빠서 이번은 아주 간단하게 이것으로 끝내겠습니다.^^;

다음에는 문자열 변환에 대해서 설명하겠습니다.

 

 

참조

http://mag.autumn.org/Content.modf?id=20050507224044

 

 

[Step. 04] nullptr, interior_ptr, pin_ptr

C++/CLI 2010. 6. 25. 08:30 Posted by 알 수 없는 사용자

nullptr

 

C/C++에서 포인터를 초기화 할 때 ‘NULL’을 사용합니다. 그러나 VC++ 10에는 C++0x에서는 포인터를 초기화 할 때 NULL 대신 새로 생긴 ‘nullptr’을 사용할 수 있게 되었습니다.


C++/CLI는 이전부터 nullptr이 있었습니다.

C++/CLI에서는 ref 클래스의 핸들을 초기화 할 때는 nullptr을 사용합니다.

C++/CLI, C++0x nullptr C/C++ 처럼 ‘0’이 아니라는 것을 잘 기억하시기 바랍니다.

 

 

 

interior_ptr

 

interior_ptr은 관리 힙(managed heap. GC겠죠) 상의 value type나 기본형을 가리키는 포인터라고 할 수 있습니다. interior_ptrvalue type나 기본형을 비관리 코드의 포인터처럼 사용하고 싶을 때 사용하면 좋습니다.

 

< 코드 1. >

ref class REFClass

{

public:

    int nValue;

};

 

void SetValue( int* nValue )

{

    *nValue = 100;

}

 

 

int main()

{

    REFClass^ refClass = gcnew REFClass;

    SetValue( &refClass->nValue );  // 에러

}

 

위 코드를 빌드 해 보면 SetValue( &refClass->nValue ); 에서 빌드 에러가 발생합니다. 매니지드 힙에 있는 것은 그 위치가 변하므로 비 관리 코드의 포인터를 넘길 수가 없습니다. 그럼 <코드 1>를 정상적으로 빌드 하기 위해서 interior_ptr를 사용해 보겠습니다.

 

< 코드 2. >

ref class REFClass

{

public:

    int nValue;

};

 

void SetValue( interior_ptr<int> nValue )

{

    *nValue = 100;

}

 

 

int main()

{

    REFClass^ refClass = gcnew REFClass;

    SetValue( &refClass->nValue );

}

 


<코드 2> SetValue의 파라미터로 비관리 코드의 참조나 포인터를 넘길 수도 있습니다.

< 코드 3. >

#include <iostream>

 

 

void SetValue( interior_ptr<int> nValue )

{

    *nValue = 100;

}

 

int main()

{

           int nValue = 50;

           SetValue( &nValue );

 

           std::cout << nValue << std::endl;

 

           getchar();

           return 0;

}

 

그리고 interior_ptr에 대신 C++/CLI의 참조(‘%’)를 사용하는 방법도 있습니다.

 

 

 

 

pin_ptr

 

pin_ptr은 관리 힙 상의 value type나 기본형을 비관리 코드에서 포인터로 사용하고 싶을 때 사용하는 기능입니다. 가장 필요한 경우가 C++/CLI에서 기존의 비관리 코드로 만들어 놓은 라이브러리를 사용할 때입니다.

 

< 코드 4. >

ref class REFClass

{

public:

    int nValue;

};

 

void SetValue( int* pValue )

{

    *pValue = 100;

}

 

 

int main()

{

    REFClass^ refClass = gcnew REFClass;

pin_ptr<int> pValue = &refClass->nValue;

    SetValue( pValue );

pValue = nullptr;

}

 

pin_ptr에 메모리 주소를 할당하는 것을 ‘pin’이라고 부르고 사용이 끝난 후 nullptr로 초기화 하는 것을 ‘unpin’ 이라고 부릅니다. pin_ptr 사용이 끝난 후 가능한 빨리 unpin 해주는 것이 좋습니다.

 

 

 

 

interior_ptr pin_ptr의 차이점

 

interipor_ptr pin_ptr은 둘 다 관리 힙 상의 value type이나 기본형을 가리키는 포인터로 사용되지만 interior_ptr은 관리 힙 상에서 인스턴스가 이동하여도 올바르게 추적할 수 있는 포인터로 런타임의 지배하에 있습니다(즉 인스턴스가 관리 힙 상에서 이동하여도 괜찮습니다).


pin_ptr은 관리 힙 상의 value type을 비관리 코드에서 사용하고 싶을 때 사용합니다. 당연히 이 때는 관리 힙에 있는 인스턴스가 이동하면 안되므로 인스턴스의 이동을 금지합니다.

 

interipor_ptr pin_ptr의 같은 점 : 포인터처럼 사용할 수 있다.

interipor_ptr pin_ptr 다른 점 : interipor_ptr은 관리 코드 상에서 포인터로 사용하고, pin_ptr는 비관리 코드에 포인터로 넘길 때 사용합니다.

 

 

interipor_ptr pin_ptr을 공부했으니 다음에는 C++/CLI에서 비관리 C++과 혼합해서 사용할 때 어떻게 해야 하는지 설명하겠습니다.

 

 

 

 

참고

http://cppcli.shacknet.nu/cli:interior_ptr

http://cppcli.shacknet.nu/cli:pin_ptr

http://cppcli.shacknet.nu/cli:interior_ptr%E3%81%A8pin_ptr%E3%81%AE%E9%81%95%E3%81%84