티스토리 뷰

프로그래밍/관리C++

기본코드

에어버스 2018. 4. 4. 13:46

 

VisualStudio2017 기준> 아래 그림처럼 CLR 콘솔 응용프로그램을 선택한다.

 

처음 코드를 보고 공부할때는 C++ 문법과 다를게 없어 쉽게 접근할 수 있을거라 생각하고
2002년도 출판된 책으로 시작했으나 문법이 바뀌었다.

종류              1세대               현재

포인터            *                    ^

__gc class       __gc class          ref class

__gc new        __gc new          gcnew

__delegate      __delegate        delegate

__event          __event            event

 

아래 코드 2세대를 보다시피 1세대가 사용이 용이한듯 한데....1세대를 지원 안하니 아쉽다.

=======================================

1. 관리형 C++ 사용하려면

관리형 프로젝트(Managed C++)를 만들고

#using <mscorlib.dll>
using namespace System;

위 두줄을 꼭 추가해야 한다.

2.
객체 생성하면 CLR(Common Language Run-time) Heap에 생성되고, 더이상 사용하지 않을때 객체는 자동 삭제된다.

참조타입(Reference Type)으로 객체가 CLR에 의해 관리되면 가비지커렉터가 해당 객체를 관리하고 추가 작업 발생하여 속도에 영향을 미친다.
이런 단점을 극복위해 값타입(Value Type)을 지원하고, 힙이 아닌 Stack 에 저장되며
__gc 대신 __value 를 사용하면 값타입으로 사용할 수 있다.

3. .NET 구조체(관리형 구조체)는 __value 사용 - Stack에 만듬.
__value struct Point
{
   ...
};

__value 생략하면 C++ 타입 구조체가 된다.
Stack에만 저장된다. (new 연산자로 Heap 할당할 수 없다)

 4. 열거형 (enum class, enum struct)
enum class Suit { Club, Diamond, Heat, Spade };
Suit suit = Suit::Club;

5. for each
String^ proverb = L"A nod is as good as a wink to a blind horse.";
for each(wchar_t ch in proverb) // proverb 문자열들을 순회
{
  if(Char::ToLower(ch); // 소문자로 변환
}

6. 힙할당
new 대신 gcnew 사용하여 (Native)C++ 힙이 아닌 CLR힙에 할당된다.

CLR은 메모리 조각나는것을 방지하기 위해 때때로 CLR힙 메모리를 최적화 시킨다. - Gabage Collected Heap 이라고도 부른다.
CLR은 힙에 있는 각 객체를 참조하는 모든 변수를 추적하고, 주어진 객체의 주소를 포함하고 있는 변수가 없을때, 그 객체는 프로그램에서 더 이상 참조될 수 없다고 판단하고 객체를 삭제하고 메모리를 해제한다.

Gabage Collection 때문에 힙에 저장된 항목의 주소는 변경될때 즉, 데이터 항목의 위치를 다시 할당할때 그 주소가 업데이트되게 해준다. - 추적핸들(^), 추적참조자(*)를 제공

- 추적 핸들 (Tracking Handle)
CLR힙에 생성된 객체를 참조하기 위해 추적 핸들을
추적 핸들은 주소를 저장하며, 추적 핸들이 참조하는 객체가 힙을 최적화하는 동안 이동된다면 그 안에 있는 주소값은 가비지 컬렉터에 의해 자동으로 업데이트 된다. 네이티브 포인터처럼 추적 핸들을 주소 연산할 수 없으며, 추적 핸들을 형변환도 안된다.

추적 핸들 선언
형식 이름 다음에 ^ 를 사용한다.

String^ proverv; // proverv가 String^ 의 추적 핸들이 된다.
자동으로 null 로 초기화 된다. 강제로 할당할때는 proverv = nullptr;
핸들을 0 으로 초기화한다면, 값 0은 핸들이 참조하는 객체의 형식으로 변환되며 이 새로운 객체의 주소가 이 핸들에 저장된다.

int^ value = 99;
int result = 2 * (*value) = 15; // 추적핸들을 역참조할때는 네이티브 포인터에서와 같이 * 연산자 사용

int^ result;
*result = 2 * (*value) = 15;

7. 배열 - CLR힙에 할당된다.
array<int>^ data = gcnew array<int>(100); // int data[100] 와 같음

for each(int item in data) {};

for(int i=0; i<data->Length; i++)
  data[i] = 2 * (i + 1);
  data + i = 2 * (i + 1); // 배열을 주소연산할 수 없다.


array<String^>^ names = { "Jack", "Jane", "Joe", "Jessica" }; // char* names[4] 와 같음.
array<String^>^ names = gcnew array<String^> { "Jack", "Jane", "Joe", "Jessica" };

Array::Clear(data, 0, data->Length); // 모든 원소를 타입에 맞게 초기화 한다.
첫번째 인수 : 초기화할 배열
두번째 인수 : 초기화 시작 인덱스 번호
세번째 인수 : 초기화 될 원소 수

int형은 0, double 형은 0.0, String^ 형은 null 값으로 초기화 된다.

1차원 배열 정렬 : Array::Sort()
1차원 배열 검색 : Array::BinarySearch()

- 다차원배열
int rows = 4, cols = 5;
array<int, 2>^ values = gcnew array<int, 2>(rows, cols); // int value[4][5]

for(int i=0; i<rows; i++)
  for(j=0; j<cols; j++)
    values[i, j] = (i+1) * (j+1);

- 배열들의 배열
배열을 참조하는 배열
array<array<String^>^>^ grades = gcnew array<array<String^>^>(5); 
grades는 array<type>^형식에 대한 핸들

grades[0] = gcnew array<String^> { "Louise", "Jack" };
grades[1] = gcnew array<String^> { "Bill", "mary", "Ben", "Joan" };
grades[2] = gcnew array<String^> { "Jill", "Will", "Phil" };
grades[3] = gcnew array<String^> { "Ned", "Fred", "ted", "Jed", "Ed" };
grades[4] = gcnew array<String^> { "Dan", "Ann" };

아래 코드와 같다.

array<array<String^>^>^ grades = gcnew array<array<String^>^>
{
    gcnew array<String^> { "Louise", "Jack" };
    gcnew array<String^> { "Bill", "mary", "Ben", "Joan" };
    gcnew array<String^> { "Jill", "Will", "Phil" };
    gcnew array<String^> { "Ned", "Fred", "ted", "Jed", "Ed" };
    gcnew array<String^> { "Dan", "Ann" };
}

8. 문자열

System::String 클래스는 System::Char 형식 문자들로 구성된 문자열

- 문자열 연결 : +
- 문자열 수정 : Trim(), PadLeft(), PadRight(), Toupper(), Insert(), Replace()
- 문자열 비교 : Compare()
- 문자열 검색 : StartWith(), EndWith(), IndexOf(), IndexOfAny()

9. 추적 참조자

CLR힙에 있는 어떤것에 대한 별칭
%연산자 이용

10. 인테리어 포인터 

추적 핸들안에 있는 주소에 대한 계산이 불가한데 이를 가능하게 한다.
interior_ptr 연산자 이용
nullptr 로 초기화된다.

array<double>^ data = { 1.5, 3.5, 6.7, 4.2 };
interior_ptr<double> pstart = &data[0]; // pstart = data; 와 같은 의미
<> 사이에는 참조할 데이터형이 오고, &연산자로 배열 첫번째 원소에 대한 주소로 포인터를 초기화 한다.

interior_ptr<double> pend = &data[data->Length-1];
double sum = 0;
while(pstart <= pend)
   sum += *pstart++;

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28