2009년 9월 28일 월요일

[C++/CLI] error C3767 "후보 함수에 액세스할 수 없습니다."

error C3767 "후보 함수에 액세스할 수 없습니다."




 Native Code 를 C++/CLI 로 Wrapping 하다 보면 아래와 같은 오류 메시지가 발생할 수 있다.


error C3767: ... 후보 함수에 액세스할 수 없습니다.
error C3767: candidate function(s) not accessible

코드에서는 GetMemFileEx 의 접근 지정자가 분명히 "public" 인데도 불구하고 저 메시지가 나온다. 당황스럽다...
GetMemFileEx 가 리턴하는 값이 private 멤버변수의 포인터 이기에 해당 멤버 변수 또한 public 으로 변경하여도 똑같다.
무엇이 문제일까..





■ 원인

우선 error C3676 에러는 크게 2가지 경우에 발생하는 에러 메시지 이다. 그중 하나가 바로 아래와 같다.
C++/CLI 에서 기본적으로 Native Type 은 다른 Assembly 에 public 접근 지정을 갖지 않는다. 즉 private 접근 지정을 갖는다.
이것은 C++/CLI 의 컴파일 옵션인 /clr 에서 컴파일 과정중에 접근 지정자가 private 로 변경된다.


위와 같이 나의 코드에서 Native Type 인 CMemFileEx 의 접근 지정자가 컴파일 과정중에 private 로 변경된다.
(ref class 인 CCliMemFileEx 에서의 m_pMemFileEx 의 접근 지정자 private 와는 상관 없다.)


위와 같이 다른 Assembly 에서 CMemFileEx 타입의 사용에 있어서 error C3767 에러가 발생하게 된다.
(CLogInRequestPacket() 생성자의 인자가 CMemFileEx * 이다.)
Managed code 의 메소드에서 Native type 을 사용하려 할 때 발생한다.




■ 해결 방법

#pragma make_public() 을 이용한다.
make_public 은 Native type 이 public assembly 접근성을 갖게 해준다. 따라서 native type 이 컴파일 과정중에 private 접근성으로 바뀌지 않게 해준다. 자세한 사용방법은 MSDN을 참조.


나의 코드에서는 #pragma make_public() 을 사용한 모습이다.




■ History

2009.09.28 - 포스팅




■ 참조
1. Compiler Error C3767 (MSDN)
2. Strange C3767 error and constructor inheritance (gamedev.net)
3. make_public (MSDN)
4. error C3767: candidate function(s) not accessible between 2 clr dlls (Visual C++ Develop Center)

2009년 9월 26일 토요일

[C++/CLI] enum

enum




 C++/CLI 에도 열거형이 있다. Managed enum 이라고도 한다.
Managed enum 을 선언할 때는 "enum class" keyword 를 사용한다.

전형적인 열거형 선언은 다음과 같다.



■ Native enum 과의 차이점

1. Managed enum 은 반드시 이름을 갖어야 한다.
익명의 Managed enum 은 사용할 수 없다.

2. Managed enum 은 사용 영역(Scope) 이 존재한다.
따라서 Managed enum 의 값에 접근하기 위해서는 Managed enum 의 이름을 통해서 접근해야 된다.

3. Managed enum 의 기초 타입은 integer 이다.
하지만 int, short, long, char, bool 모두 사용 가능하다. 아래 예는 bool 타입이 기초 타입인 Managed enum 이다.






■ 참조
1. Quick C++/CLI - Learn C++/CLI in less than 10 minutes (CodeProject)

[C++/CLI] Value Type - struct

Value Type - struct


 Value Type 은 기본 타입(Primitive Type) 외에 새로운 타입을 만든 것이라고 할 수 있다. .Net 에서 모든 타입은 System::Object 클래스를 상속 받는다. 모든 Value Type 은 System::ValueType 클래스를 상속받는다.


Value Type 은 메모리가 스택에 할당된다. 모든 기본타입(Primitive Type) 과 구조체(struct) 는 Value Type 이다.
Value Type 은 Equal 연산자(=) 를 사용하여 할당 될 수 있다.

다음은 구조체(struct) 의 예 이다.


C++/CLI 의 struct 생성 key word 는 "value struct" 이다.
C++, C# 과 마찬가지로 struct 는 생성자를 갖을 수 있다.





■ 참조1. Quick C++/CLI - Learn C++/CLI in less than 10 minutes (CodeProject)


[C++/CLI] Hello World 예제

Hello World 예제




■ C++/CLI 클래스 라이브러리를 이용한 예제

1. 프로젝트 생성


Visual Studio 2008 에서 프로젝트를 생성한다.
"파일" → "새로 만들기" → "프로젝트" 를 선택한다.
템플릿 선택은 다음과 같다.
"Visual C++"  → "CLR" → "클래스 라이브러리"


2. 생성되는 파일 확인


 Solution Explorer 를 보면 위와 같은 구조로 파일들이 생성된다.
MFC 프로그래밍 시 익숙한 "Stdafx.h" 가 보인다. 즉, C++/CLI 도 미리 컴파일된 헤더를 지원한다.
프로젝트에서 자주 사용되지만, 자주 변경되지 않는 헤더 파일들을 이곳에 선언해 주자.
 실제적으로 코딩해 주어야 하는 곳은 "HelloWorldCLI.cpp", "HelloWorldCLI.h" 파일이다.


3. 클래스 작성




C++/CLI 는 CLR 에서 동작되는 프로그램 이기 때문에 C# 에서와 같이 System 클래스를 참조할 수 있다. 따라서 System::Console::WriteLine() 과 같은 BCL(Base Class Library) 를 이용할 수 있다.
namespace 가 존재한 다는 것을 주의하자.


4. dll 파일 생성


위 코드를 컴파일 하면 클래스 라이브러리 프로젝트 이므로 dll 파일이 생성된다.
이제 이 dll 파일을 다른 .NET 응용프로그램에 참조 시켜서 사용 하기만 하면 된다.


5. C# 콘솔 응용프로그램으로 테스트

HelloWorldCLI 솔루션에 HelloWorldCLI 이름의 C# 콘솔 응용프로그램 프로젝트를 추가 시킨다.




HelloWorldCLI 에서 만들어진 dll 파일을 직접 참조 시켜도 되고, 지금은 같은 솔루션에 존재하기에 "프로젝트" 탭에서 HelloWorldCLI 프로젝트를 참조 추가 시켜 준다.




메인 함수 코드 및 출력 결과이다.
cfile9.uf.120CFB3850AEC2C02AE3A5.zip





■ C++/CLI 콘솔 응용프로그램 예제
1. 프로젝트 생성


Visual Studio 2008 에서 프로젝트를 생성한다.
"파일" → "새로 만들기" → "프로젝트" 를 선택한다.
템플릿 선택은 다음과 같다.
"Visual C++"  → "CLR" → "CLR 콘솔 응용프로그램"


2. 생성되는 파일 확인

C++/CLI 클래스 라이브러리 프로젝트와 비교해 보면 HelloWorld2.cpp 파일이 하나 생긴다. 클래스가 아니기 때문에 헤더파일은 만들어 주지 않는다.


3. 메인 함수 작성 및 출력


C, C++ 의 main 함수와 마찬가지로 C++/CLI 도 Main 함수가 응용프로그램의 Entry Point 이다. C# 콘솔 응용프로그램을 작성하게 되면 Main 함수의 Syntax 는 다음과 같다.

int Main(String[] arg) {...}

물론 C# 에서 Main() 함수의 Syntax 는 리턴값과 매개변수의 종류에 따라 4가지가 되긴 하지만, 아마도 위 형태가 맵핑 되는 형태같다. 이로서 알 수 있는 것은 C# 에서 System.String[] 의 타입은 C++/CLI 에서 array<System::String^>^ 과 맵핑됨을 유추할 수 있다.
 .NET Framework 프로그램밍 언어들은 ANSI 코드를 사용하지 않고 UNICODE 를 지원한다. 따라서 WriteLine 함수의 인자도 UNICODE 형태로(L"Hello World") 작성되어 있다.

cfile7.uf.016C9B4050AEC2C01227A9.zip



■ History

1. 2009.09.26

2009년 9월 24일 목요일

[C++/CLI] Handle and Pointers

Handle and Pointers




" C++/CLI 는 C++, C#, VB.NET 에서 .NET 프로그래밍을 한다는 것을 의미 " 을 되세기면서!!
C++ 에서 포인터를 표시하기 위하여 '*' 를 사용한다. '*' 는 CRT(Common Run-Time) Heap 에 존재하는 Native Pointer 를 위해 디자인 되었다.
C++/CLI 에서 '^' 는 Handle 을 의미한다. '^' (Handle) 은 Managed Heap 에 존재하는 Managed Pointer 와 "Safe Pointer" 를 위해 디자인 되었다.




■ Handle

Handle 은 참조(Reference) 비슷하다. 하지만 Native Pointer 와는 같지 않다. 즉, Handle 은 Gabage Collector 가 메모리를 관리해주기 때문에 Memory leak 을 일으키지 않는다.
Handle 은 프로그램이 실행되는 동안에 이동될 수 있기 때문에 고정된 메모리 주소를 갖지 않는다.




■ Handle 의 생성

어떠한 클래스나 Value Type 의 새로운 Reference 를 생성하기 위해서는 gcnew 키워드로 생성한다.





■ Tracking Reference - %

C++ 에는 포인터 * 가 있다. 또한 Reference 라고 하여 & 를 지원한다.
이와 같은 목적으로 C++/CLI 에 Handle ^ 가 있다면 이를 편하게 사용할 수 있는 Tracking Reference % 가 있다.
사용 예는 다음과 같다.








■ nullptr

nullptr 은 null Reference 를 나타낸다. 자세한 내용은 아래 링크를 참조
nullptr




■ 참조

1. Quick C++/CLI - Learn C++/CLI in less than 10 minutes (CodeProject)
2. gcnew
3. nullptr

2009년 9월 22일 화요일

[C++/CLI] interior_ptr

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)




2009년 9월 21일 월요일

Classes Shared by MFC and ATL

Classes Shared by MFC and ATL



 이게 몬 소리일까??
예전부터 MFC 로 코딩할 때 CString 을 MSDN 에서 찾아보면 ATL 어쩌구 저쩌구... 나온다. 내심 CString 은 MFC 의 클래스가 아닌가 의문을 품었었는데... 그러다 또 COleDateTime 이라는 클래스를 사용할 때도 ATL 관련 어쩌구 저쩌구... 나온다.

 Visual C++ .Net 2002 부터 몇몇개의 유용한 MFC 유틸리티 클래스들은 MFC 와의 의존성을 없애고 Native C++ 프로젝트에서 사용할 수 있도록 다시 작성되고 교정 되었다. 따라서 MFC 프로젝트가 아닌 Win32 프로젝트 같은 프로젝트에서 사용하려는 클래스의 헤더파일만 include 해주면 해당 클래스를 사용할 수 있다.

대부분의 파일들은 atlbase.h 파일이 먼저 include 되어 있어야 제대로 동작된다. atlstr.h 파일의 경우에는 atlbase.h 가 include 되어 있어 신경 써주지 않아도 되지만, atltypes.h 에는 atlbase.h 가 include 되어 있지 않으므로 atltypes.h 를 include 하기전에 atlbase.h 를 먼저 선언해 주어야 한다. 그렇지 않으면 링크 에러가 난다.

MSDN 에서 MFC 와 ATL 에서 공유 가능한 클래스 리스트중 일부는 다음과 같다.
자세한 목록은 아래 MSDN 을 참조.




■ History

2009.09.21 - 포스팅
2009.09.29 - atlbase.h 내용 추가


■ 참조

1. ATL/MFC Shared Classes (MSDN)
2. Classes Shared by MFC and ATL (MSDN)
3. ATL/MFC Shared Classes (Tistory blog)

2009년 9월 20일 일요일

[C++/CLI] Boxing, UnBoxing

Boxing, UnBoxing



 .Net Framework 에서 동작하는 Managed Code 의 데이터 타입은 Value Type, Reference Type 2가지가 있다. Value Type 은 스택에 메모리를 할당 하는데 프로그래밍을 하다 보면 Value Type 을 스택이 아닌 Managed Heap 에 할당할 필요가 생긴다. 이렇게 Value Type 과 Reference Type 간의 형변환 과정에서 Boxing 과 UnBoxing 이 발생하게 된다.


■ Boxing & UnBoxing
Boxing     : Value Type → Reference Type
UnBoxing : Reference Type → Value Type

Boxing  과 UnBoxing 의 발생은 내부적으로 많은 리소스를 소비하게 된다. 따라서 불필요한 메모리 생성 및 어플리케이션의 성능 저하를 일으킨다. (cf. C# 은 System.Object 를 최상위 클래스로 하여 이러한 Boxing/UnBoxing 이 많이 일어 났는데 이를 보완하기 위해 .Net Framework 2.0 에서 제네릭 문법이 추가 되었다.)


1. Boxing



Value Type 인 int 타입을 Boxing 하는 예이다.  int 타입을 메소드의 인수로 전달하기 위해 System::Object^ 타입으로 Boxing 한다. System::Object 타입은 모든 타입의 부모 클래스 이기에 가능하다.


2. UnBoxing



Boxing 의 반대 동작으로서 Managed Heap 에 할당된 인스턴스의 값을 탐색하여 스택에 값을 로드한다.





■ 참조
1. C++/CLI Primer - Enter the World of .NET Power Programming
2. safe_cast (MSND)

[C++/CLI] nullptr

nullptr




 Managed 객체 참조는 C++ 의 포인터와 한가지 면에서(객체를 가리키는 또는, 무언가를 가리킨다는 점에서) 유사하다. C++ 포인터의 값이  NULL 일때, 포인터는 메모리의 어떠한 위치도 가리키지 않는다. 유사하게 객체 참조(Managed Code 의)가 아무것도 가리키지 않을 때 객체 참조는 nullptr 값을 갖는다. nullptr 은 C++/CLI 의 키워드 이다. 이것은 int, float 와 같이 타입의 종류가 아니다. 이 값은 객체 참조가 어떠한 것도 가리키지 않는다는 것을 나타낸다. nullptr 은 타입이 아니기 때문에 sizeof(nullptr), throw nullptr 과 같이 사용할 수 없다.


1. 객체 참조에 할당



2. 유효한 객체 참조에 명시적으로 할당


유효한 객체 참조에 nullptr 을 할당 하므로서, 해당 객체 참조가 더이상 참조 되지 않음을 나타내고, Garbage Collector 의 수집 후보가 된다.


3. 객체 참조의 비교 연산으로 사용
   if (dirObjRef == nullptr) { throw some exception or as you wish...}
   if (dirObjRef != nullptr) {....}

   즉  ==, != 과 같은 비교 연산과 사용 가능하지만 +, -, >, <, etc 연산자들과는 사용할 수 없다.


4. 매소드의 인자 또는, 리턴값으로 사용





5. nullptr 은 Managed Code 및 Native Code 에서 호환 가능하다.




■ 참조

1. C++/CLI Primer - Enter the World of .NET Power Programming

[C++/CLI] cli::array^



cli::array<t>^<t>









 C++/CLI 에서 배열은 하나의 Data type 이다. 어떠한 배열이든 cli::array 클래스의 인스턴스(참조 타입)이다.

메모리는 동적으로 CLR(Common Language Runtime) Heap 에 생성된다. 메모리의 크기는 배열 생성시에 결정되며 그 이후에는 크기를 변경할 수 없다.


 




1. 만약 배열의 Data Type Value Type 이라면 배열 생성 시 Boxing 되어 들어간다.

(Boxing 과정은 프로그램의 Performance 를 하향 시킨다.)

2. 배열의 인덱스(첨자) 0 부터 시작한다.

3. 배열은 배열의 요소에 접근 및 다루기 위한 메소드를 가지고 있다.

4. 배열에서의 모든 동작은 체크된다. , 배열의 범위를 넘어가는 동작에 대하여 “Index out of range”

예외가 발생하게 된다.

5. 배열은 CLR Heap 에 할당된다. Value Type 의 배열은 Heap Boxing 된 다음 그 참조를 리턴받는다.



 



■ 사용 예



int 타입의 배열 a 를 선언 및 생성 하였다. 또한 배열의 개수를 명시적으로 선언하지 않고, 초기화 값을 선언하였으므로 묵시적으로 1, 2, 3 의 값을 갖는 크기 3의 배열이 생성된다.




위 예는 명시적으로 배열의 크기를 100으로 선언하였다. 따라서 100 개의 요소를 갖는 배열이다. 또한 1,2,3 으로 초기값을 적어주었으므로 배열의 처음 3번째 요소까지 초기화가 이루어 진다.




cli::array 클래스에는 배열을 조작하기 위한  메소드와 프로퍼티가 정의되어 있다. Length, index 등 이 있으며 foreach 문에서 사용할 수 있다.

 

위의 예는 다차원 배열의 선언 및 사용 예이다. array<type, 차원>^ 과 같이 사용한다. 위의 예는 3차원 배열로서 4*5*2 크기를 갖는 배열이다.




String 클래스의 배열 역시 사용할 수 있다. 인상적인 것은 <> 안에 String^ 이 들어간다.




위의 예는 String 클래스의 배열을 생성 후 루프를 돌면서 초기화 하는 예제 이다.





■ 가변인자 사용 예

C++ 과 마찬가지로 가변 인자 를 지원한다. 다음은 사용 예 이다.





※ 만약 배열에 요소를 추가 하거나 삭제 하려 한다면 ArrayList 클래스를 참조한다.







■ 참조