interior_ptr




 Reference Type 내부를 가리키는 포인터를 선언한다. 즉, C++/CL 에서 사용되는 객체 참조를 가리키는 포인터를 말한다.
interior 란 단어의 사전적인 의미가 "안쪽의, 내부" 라는 뜻이다. ptr 은 "pointer" 의 약자 일테고. 즉, Managed Heap 의 인스턴스를 가리키는 객체 참조가 있지만 객체 참조가 가리키는 안쪽의 인스턴스를 가리킨다는 의미가 아닐까?! 풋 ㅎㅎ

interior_ptr 이 가리킬 수 있는 것은 아래와 같다.

    - Reference Handle (객체 참조)
    - Value Type
    - Boxed type Handle
    - member of managed type
    - element of a managed array


C++/CLI 에서 포인터는 2가지가 있다.

- Native Pointer
- Managed Pointer(interior_ptr, pin_ptr)

Native Pointer 사용시 문제가 발생할 수 있다. Native Pointer 가 Managed Heap 의 객체를 가리키게 한다면 Managed Heap 의 객체는 Gabage Collector 의 메모리 최적화 기능에 의해 객체의 주소가 변경되게 된다. 하지만 Native Pointer 는 객체가 이동되기 전의 주소를 계속 가리키고 있기 때문에 Native Pointer 를 이용하여 연산 한다면 엉뚱한 결과를 초래하게 된다.

 CLR 은 interior_ptr 을 인식하다. CLR 은 자동으로 객체의 새로운 위치를 가리키는 interior_ptr 값을 갱신해 준다.
즉, interior_ptr 이 가리키는 Managed Heap 의 인스턴스의 주소는 계속 변경이 된다. 하지만 CLR 이 변경된 주소를 자동으로 interior_ptr 값을 변경시켜주어 가리키고 있는 객체를 유지하게 해준다.





■ Syntax



- cli namespace 를 갖는다.




■ Parameter

- cv_qualifier
   const 또는 volatile 지정자, 생략 가능하다.

- initializer
   참조 타입의 멤버, element of managed array, 또는 native pointer 에 할당 가능한 어떠한 객체

- type
   initializer 의 타입

- var
   interior_ptr 변수의 이름




■ 예제 1

헷갈리니 예제를 보면서 이해해야 겠다. 아래 코드는 MSDN 의 예제 코드이다.



C++/CLI 에서 Reference Type 으로서 Gabage Collection 이 관리할 수 있도록 MyClass 을 ref class 로 정의한다. 따라서 이 클래스의 인스턴스는 gcnew 로 생성하게 된다.

클래스 인스턴스를 생성할 때 클래스 이름 뒤에 ^ 를 붙이므로서 해당 변수가 참조 타입임을 컴파일러에게 알려준다. 따라서 h_MyClass 변수는 gcnew 를 통해서 생성해야 됨을 의미!!

think!!
C++/CLI 코드에서 Console::WriteLine() 코드를 사용할 수 있네?! +_+
그렇다면 모든 BCL(Base Class Library) 를 사용할 수 있는 것인가??

h_MyClass 는 객체 참조로 생성 되었다.(Reference Type 이며, Managed Heap 에 생성)  여기서 h_MyClass 의 필드인 data 의 주소를 가리키는 interior_ptr 을 생성한다. 즉 객체 참조 안에 data 를 가리키는 포인터를 생성한 것이다.

interior_ptr syntax 에서
initializer 는 h_MyClass->data 이다. h_MyClass->data 는 참조 타입의 멤버 이므로 가능하다. 포인터에는 당연히 주소를 넘겨야 하므로 &연산자를 붙여 줬다.

type 은 int 이다. initializer 의 데이터 타입이므로 h_MyClass->data 의 타입인 int 가 된다.

var 는 p 이다. 생성한 interior_ptr 의 변수 이름이 된다.

cv_qualifier 는 생략 되었다.

interior_ptr<MyClass ^> p2 = &h_MyClass; 에서는
p2가 h_MyClass 인스턴스(객체 참조)가 된다. type 에는 h_MyClass 의 타입인 MyClass^ 을 사용하였다.





■ 예제 2

다음과 같은 테스트 클래스가 있다고 하자.



테스트 함수는 다음과 같다.


이 함수는 10000 번의 루프를 돌아 Test 클래스 인스턴스를 생성한다.
목적은 Managed Heap 을 0 메모리로 만들기 위함이다. (별 의미는 없다.)


테스트 메인 함수는 다음과 같다.


DoLotsOfAllocs 함수를 실행시켜 Managed Heap 메모리를 0 으로 만든다.
Test 클래스를 Managed Heap 에 생성한다. 생성한 인스턴스를 t 참조 객체가 가리키게 된다.
t 를 이용하여 멤버 변수 m_i 값을 99 로 설정한다.
p 라는 interior_ptr 포인터를 생성하여 t 의 m_i (참조 객체의 멤버)를 가리키게 한다.
다시 DoLotsOfAllocs 함수를 실행시켜 Managed Heap 메모리를 기록한다. 이때, Gabage Collector 가 Managed Heap 을 최적화 하게 되고 인스턴스 t 의 메모리 주소가 변경되게 된다.
p 는 interior_ptr 의 특성에 따라 변경된 t 의 주소(m_i) 를 가리키게 된다.


출력 결과는 다음과 같다.


즉, interior_ptr p 가 가리키는 주소는 Managed Heap 의 객체의 주소에 따라 변경 되지만 p 가 가리키는 객체는 유지가 된다.





■ 예제 3 - Passing by reference using interior pointers

interior_ptr 타입을 함수의 인자로 사용하는 예제이다.
C++/CLI 클래스 및 함수는 다음과 같다.


전달 받은 인자의 값을 제곱한 것으로 설정하는 함수이다.
눈여겨 볼 것은 Square 함수의 인자로 interior_ptr 을 사용하는 방법!


테스트 메인 함수는 다음과 같다.



출력 결과는 다음과 같다.


Square() 함수의 인자가 interior_ptr<int> 타입이기에 interior_ptr<int> 타입 p 는 바로 전달하며 p 가 가리키는 값도 변경되었다.
그 다음 눈여겨 봐야 할 것은 Square() 함수 인자에 Native Pointer 를 넘겨주었는데도 제대로 동작한다는 것이다.  (변수 a 에 주소 연산자 & 를 사용하여 주소을 얻었으므로 그것은 Native Pointer 가 된다.)  이것이 가능한 이유는 Native Pointer 를 interior_ptr 로 넘겨줄 때 자동으로 interior_ptr 로 변환 된다. (역으로 interior_ptr 은 Native Pointer 로 변환 할 수는 없다.) 
아래 Remarks 에서 언급된
" interior_ptr 은 native pointer 가 할당 받을 수 있는 것 역시 할당 받을 수 있다. 또한 비교와 포인터 연산 같은 native pointer 에사 사용할 수 있는 기능을 사용할 수 있다."
이 말은 이런 것을 의미하는 것이다.


위에선 이래저래 * 과 & 이 많이 달라 붙으면서 조금 복잡해 보인다. C++/CLI 에서는 Tracking Reference [%] 를 지원한다. % 를 사용하여 interior_ptr 을 함수 인자로 사용하는것과 동일한 동작을 할 수 있다.

테스트 할 함수는 다음과 같다.


눈에 띄는 것은 역시 함수 인자에 Tracking Reference 인 % 가 붙은 것이다. 함수의 동작은 위의 Square 와 동일 하다. 전달받은 인자인 pNum 을 마치 지역 변수 인 것처럼 사용하고 있다.


테스트 메인 함수는 다음과 같다.


위의 테스트 함수와는 다르게 Square2() 함수의 인자에 마치 지역 변수를 넘기듯 넘겨 주었다. 하지만 예상했던 동작대로 객체 참조 멤버 값이 변경 되었다. Tracking Reference 와 interior_ptr 은 내부적으로 동일한 동작을 한다. 마치 C++ 의 참조 타입을 전달하는것 과 비슷해 보인다.





■ 예제 4 - Pointer arithmetic with interior pointers

interior_ptr 은 Native pointer 와 같은 포인터 연산이 가능하다.

아래 코드는 int 배열의 포인터 연산 예이다.


cli::array 로 int 형 배열 arr 을 선언하였다. 또한 interior_ptr p 가 arr 을 가리키게 하였다.
&arr[0] + arr->Length 는 arr 배열의 마지막 요소의 끝 주소를 가리킨다. 따라서 p 가 arr 배열의 모든 요소를 순회 하게 된다.
interior_ptr p 를 포인터 연산에 어떻게 사용하였는지 눈여겨 보자.


다음의 코드는 System::String 을 직접 조작하는 코드이다.


아마 눈에 띄는것은 System::String^ 타입을 interior_ptr 로 변환하는 방법일 것이다.
복잡하게 다음과 같이 사용할 수도 있다.






■ Remarks

 Native pointer 는 managed heap 에서의 아이템 위치 변경과 같이 아이템을 추적할 수 없다. Managed Heap 에 있는 객체의 인스턴스는 Gabage Collector 가 managed heap 을 최적화 하는 과정에서 위치가 변경되기 때문이다. 포인터가 위치 변경된 객체의 인스턴스를 가리키게 하기 위해선 포인터를 갱신 하여야 한다. 
 
 interior_ptr 은 native pointer 가 할당 받을 수 있는 것 역시 할당 받을 수 있다. 또한 비교와 포인터 연산 같은 native pointer 에사 사용할 수 있는 기능을 사용할 수 있다.

 interior_ptr 은 스택에 선언되어진다. 클래스의 멤버로 선언되어질 수 없다. (즉, 지역 변수로 사용되며 전역적으로는 사용할 수 없다.)

 interior_ptr 이 조건문에 사용되었을 때, 묵시적으로 bool 타입으로 변환 된다.

 Gabage Collector 에 의해 이동되지 않는 포인터는 pin_ptr 을 참조

 interior_ptr 은 ref object 를 가리키는데 사용할 수 없다.
 interior_ptr<System::String> 은 허용되지 않는다. interior_ptr<System::String^> 은 옮바른 문법이다.

 interior_ptr 은 명시적으로 초기화 값을 주지 않는다면 default 로 nullptr 값으로 초기화 된다.





■ 참조

1. interior_ptr (MSDN)
2. An overview of interior pointers in C++/CLI (CodeProject)




Posted by six605
,