#cpp primer plus #cpp primer

 

컴퓨터 프로그램이 data를 저장할 때 반드시 따라오는 3가지 기본적인 특징이 있다.

  • information이 어디에 저장되는지
  • 무슨 값(value)이 거기에 있는지
  • 어떤 종류의 information이 저장되어 있는지

우리들은 이러한 목적들을 알기 위해 한가지 전략을 사용해왔다: 바로 간단한 variable을 정의하는 것.

declaration statement(선언문)은 값에 대한 type과 symbolic name을 제공한다. 이것 또한 프로그램이 값에 대한 memory를 할당하고 내부적으로 그 위치를 쫓아가도록 한다.

범한 variable(fundamental type variable을 의미)을 사용해서, value을 이름이 있는 양(a named quantity)로 간주하고 그 위치를 유도된 양(a derived quantity)으로 본다.

 

이번엔 두번째 전략을 보자, 이것은 발전하는 c++ class 영역에서 특히 더욱 중요해지는 부분이다. 이 전략은 바로 value 자체 보다는 value의 주소를 저장하는 variable인 pointer에 있다.

 

pointer 전략은 memory management라는 c++ 프로그래밍 철학이다.

 

 

Pointer와 C++철학

 

OOP(Object-oriented programming)는 compile time 대신에 runtime 동안 결정 내리는 것을 강조하는 점에서 전통적인 절차지향 프로그래밍과 다르다. Runtime은 프로그램이 진행되는 동안을 의미하고 compile time은 compiler와 프로그램이 함께 놓인 상태를 의미한다.

runtime decision은 마치 우리가 방학 중에 그 때의 날씨나 분위기에 따라서 어디를 보러갈지 선택하는 것인 반면에 compile-time decision은 조건과 관계없이 사전 스케줄을 더 고집하는 것이다.

runtime decision은 현재 상황에 적응할 수 있는 flexibility를 제공한다. 예를 들어, array에 대한 memory를 할당한다고 해보자. 전통적인 방법은 array를 선언(declare)하는 것이다.  c++에서 array를 선언하기 위해서는 특정 array size를 정해줘야 한다. 따라서 그 array size는 프로그램이 compile되는 동안에 결정된다; 이것이 바로 compile-time decision이다(쉽게 말하자면, source code를 짜는 순간을 의미). 우리는 20개의 data를 저장하기 위해 안전하게 200개의 원소를 가진 배열을 사용한다고 하자. 이것은 memory waste를 초래한다.

이 방식은 프로그램이 진행된 후에 오직 20개의 원소만 필요하다고 프로그램에 말할 수 있다.

요약하자면, OOP를 사용해서 array size를 runtime decision 하고 싶다. 이 접근이 가능하려면, language는 program이 진행되는 동안 array를 만들 수 있도록 허락해야만 한다.  곧 보겠지만, c++ method는 memory의 적합한 크기를 요구하기 위해 'new' keyword를 사용하고 새롭게 할당된 메모리가 발견된 곳을 추적할 수 있도록 pointer를 사용하는 것을 포함한다.

 

runtime dicision은 OOP에서만 독특한게 아니다. 하지만 C++은 C가 하는 것보다 더욱 직관적으로 코드를 짜도록 만든다.

 

 

 

 

 pointer를 사용할 때 아주 조심해야할 부분에 대해 살펴보자.

위험은 pointer를 무분별하게 사용하는 사람들을에게 나타난다. 한 가지 중요한 포인트는 C++에서 pointer를 declare(선언)할 때, 컴퓨터는 주소를 보관할 memory를 할당한다. 하지만 주소가 point하는 data를 보관할 memory를 할당하는 것은 분리된 하나의 다른 절차이다. 그 절차를 생략하는 것은 재앙으로의 길로 안내한다:

 

long* fellow;            //create a pointer to long

*fellow= 223323;       

 

확실히, fellow 변수는 pointer이다. 하지만 fellow는 어디를 가리키는가? 이 코드는 fellow에 주소를 할당하지 못한다. 그렇다면 value 223323은 어디에 위치하는가? 우리는 알수 없다. fellow는 초기화되지 않았기 때문에, 어떠한 value도 가지고 있지 않다. 이런 류의 error는 대부분 함정에 빠뜨리고 추적하기 힘든 버그들을 만들어낸다.

 

Pointer Golden Rule: pointer 변수에 dereferencing operator(*)를 적용하기 전엔 항상 pointer 변수를 분명하고 적절한 주소로 초기화해라 

 

 

 

이번엔 주소를 보관하는 pointer와 그 주소값인 number의 관계에 대해 살펴보자.

pointer는 integer 타입이 아니다. 물론 컴퓨터는 기본적으로 주소를 integer로 다루지만말이다. 개념적으로, pointer는 integer와 다른 타입이다. integer는 더하고 빼고 나누고 등을 할 수 있는 숫자이다. 반면 pointer는 위치를 나타내고 예를들어, 두개의 위치를 서로 곱하는 것은 말도 안된다. 이런 관점에서 pointer와 integer는 서로 다르다. 결과적으로, integer를 pointer에 간단히 할당할 수 없다:

 

int* pt;

pt = 0xB8000000;    // type mismatch

 

여기에, 왼쪽은 pointer to int이고 여기에 주소를 할당할수있지만, 오른쪽에는 그저 하나의 integer이다.

여기서 우리는 0xB8000000이란 게 노후화된 컴퓨터 시스템에서 video memory의 combined segment-offset address라는 것을 알고 있을 수도 있다. 그러나 저 문장에서는 아무것도 프로그램에게 저 숫자가 주소라고 말해주지 않는다. C99보다 먼저의 C에서는 이런 식으로 할당하게 만들지만 C++에서는 더욱 엄격히 type에 대해 강요하고, 컴파일러는 type mismatch라고 말하면서 error message를 띄운다.

만약에 nemeric value를 주소로 사용하기를 원한다면, type cast를 사용해서 숫자를 적절한 주소 type으로 바꿔줘야 한다!:

 

int* pt;

pt = (int *) 0xB8000000;    //types now match