[cpp] 메모리 사용법 1

@codemaru · August 07, 2007 · 6 min read

자본주의 사회에서는 자신의 것과 남의 것이 명확하게 구분된다. 허락 없이 남의 것을 가져가면 법적으로 처벌받는다. 이러한 원리는 컴퓨터 속 세상에도 동일하게 적용된다. 자신이 할당한 메모리가 아닌 곳을 임의로 사용하면 잘못된 연산이 수행되었다는 오류와 함께 프로그램은 종료된다. 따라서 메모리를 사용할 때에는 반드시 그 용도와 소유권을 분명히 알아야 한다.

하지만 불행하게도 C/C++은 그러한 것을 명확하게 할 수 있는 언어적 표현 방법이 존재하지 않는다. 여러 개의 변수를 동시에 리턴 할 수 없기에 함수 파라미터에 입력과 출력을 위한 것이 섞여서 사용된다. 또한 리턴 값으로 포인터가 사용되는 경우에도 그 포인터가 입력으로 들어간 파라미터의 포인터인지 누군가 내부적으로 할당한 포인터인지를 함수 원형을 통해서 알 수 있는 방법이 없다. 내 것과 남의 것이 마구 섞여서 사용되면서 누구의 것인지 표시가 없는 것과 같은 상황인 셈이다. 그래서 남의 메모리를 허락 없이 사용하고도 무엇이 잘못됐는지 모르는 일들이 벌어지곤 한다. 이런 실수를 방지하기 위해서 주의해야 할 것들에 대해서 알아보자.

파라미터의 용도

BOOL GetVersionEx(LPOSVERSIONINFO lpVersionInfo);
```위와 같은 함수 원형을 만났을 때 가장 먼저 생각해야 하는 것은 포인터 파라미터의 용도다. lpVersionInfo가 입력을 위한 것인지 출력을 위한 것인지 아니면 둘 다를 위한 것인지를 가장 먼저 판단해야 한다. 입력을 위한 것은 구조체 값을 참조만 하고 변경하지 않음을 의미한다. 출력을 위한 것은 아무 구조체나 할당된 것을 그냥 집어 넣으면 적절한 값으로 구조체를 채워 줌을 의미한다. 가장 복잡한 입출력은 구조체의 일부 멤버를 사전에 설정해서 넘겨주면 함수 내부에서 나머지 멤버를 적절한 값으로 채워서 넣어준다는 것을 의미한다. 새로운 함수를 만나면 항상 포인터 파라미터가 세 가지 중에 어디에 속하는지 파악하고 그 목적에 맞는 포인터를 파라미터로 넘겨 주어야 한다.  
  
GetVersionEx함수의 lpVersionInfo는 입, 출력을 위한 파라미터다. 함수를 호출하기 전에 반드시 dwVersionInfoSize에 구조체 크기를 저장한 다음 함수로 넘겨 주어야 한다.  
  
리턴 값의 출처  
```cpp
struct tm \*localtime(const time\_t \*timer);
```C언어에서 시간을 구할 때 사용하는 localtime의 원형이다. 적어도 C언어를 제대로 배운 사람이라면 이런 함수의 원형을 만나면 리턴 값의 출처에 대해서 의심을 해야 한다. 리턴 되는 포인터를 누가 할당한 것인지, 해제를 누가 어떻게 하는 것인지에 대해서 정확하게 알아야 한다. 일반적으로 리턴 되는 포인터는 크게 다섯 가지 부류로 나뉜다. 각 부류의 대표 함수와 특징이 <1>에 나와있다. 물론 이 다섯 가지 범위 밖의 일반적이지 않은 함수들도 존재한다. 그러한 함수들에 대해서는 반드시 포인터의 출처를 함수 매뉴얼을 통해서 숙지한 후 사용해야 한다.1 리턴 포인터의 종류




|  |  |  |
| --- | --- | --- |
| 대표 함수 | 종류 | 특징 |
| strcpy | 파라미터로 들어간 포인터 | 해제할 필요가 없다. 리턴 값을 수정할 경우 입력으로 들어간 파라미터의
 값도 같이 바뀐다. |
| strdup | malloc/new를 사용해서 할당한 포인터 | 리턴 값을 사용한 후에는 반드시 free/delete를 사용해서
 해제해 주어야 한다. |
| localtime | 전역 변수나 정적 지역 변수 포인터 | 해제할 필요가 없다. 함수를 호출하면 이전에 리턴 됐던 값이 변경
 된다. 따라서 리턴 값을 나중에 다시 사용해야 하면 반드시 별도의 메모리에 보관해야 한다. |
| CreateFile | 특수한 처리를 통해 할당된 포인터 | 사용한 후에는 할당 함수에 대응하는 해제 함수를 통해서 포인터를 제거해야 한다. CreateFile에 대응하는 해제 함수는 CloseHandle이다. |
| CWnd::FromHandle | 임시 포인터 | 해제할 필요가 없다. 이 포인터의 경우 임의로 삭제될 수 있기
 때문에 추후에 사용하기 위한 용도로 저장하지 말아야 한다. |


  

@codemaru
돌아보니 좋은 날도 있었고, 나쁜 날도 있었다. 그런 나의 모든 소소한 일상과 배움을 기록한다. 여기에 기록된 모든 내용은 한 개인의 관점이고 의견이다. 내가 속한 조직과는 1도 상관이 없다.
(C) 2001 YoungJin Shin, 0일째 운영 중