6월호 기사에서 우리는 함수로 넘어오는 인자와 함수의 리턴 값에 사용되는 메모리의 종류와 사용 방법에 대해서 배웠다. 하지만 실제 프로그램을 작성할 때에는 인자와 리턴 값 외에도 신경 쓸 부분이 많다. 이번 시간에는 Windows 메시지에 사용된 복잡한 특성의 메모리와 스마트 포인터를 사용해서 메모리 릭을 방지하는 방법에 대해서 살펴본다.
복잡한 특성을 가진 메모리
LVN_GETDISPINFO는 리스트 뷰 컨트롤에서 추가한 아이템의 내용을 콜백으로 설정하도록 했을 때 날라오는 메시지다. 이 메시지의 파라미터로는 LVITEM이 넘어온다. 대부분의 초급 Visual C++ 책에서는 이 메시지 핸들러에 다음과 같은 코드를 포함하고 있다.
strcpy(item->pszText, \_T(“태권브이”));
```아주 단순한 코드다. 그런 만큼 책에는 저 코드에 대한 어떠한 설명도 없다. 하지만 우리는 저러한 코드를 보면 “pszText에 대한 할당과 해제를 책임지는 것은 누구일까?”라는 질문을 꼭 던져야 한다.
pszText는 꽤나 복잡한 성격의 포인터다. 복사할 문자열의 길이가 cchTextMax보다 작다면 위와 같이 문자열 복사를 하면 된다. 만약 복사할 문자열이 더 길다면 pszText가 가리키는 포인터를 아래와 같이 바꾸어 주면 된다. 이 때 한 가지 주의해야 할 점은 pszText가 가리키고 있는 메모리가 적어도 두 번의 LVN\_GETDISPINFO 메시지를 더 받은 다음 파괴되어야 한다는 점이다.
```cpp
item->pszText = \_T(“태권 브이”);
```위와 같이 복잡한 특성은 LVN\_GETDISPINFO를 설계한 사람이 아니라면 알 수 없기 때문에 API를 만든 사람은 친절하게 매뉴얼에(MSDN) 설명을 적어 놓았다. 따라서 위와 같이 이상하게 보이는 메모리가 있다면 반드시 매뉴얼을 통해서 그 메모리를 다루는 방법에 대해서 숙지한 다음 사용하도록 해야 한다.
스마트 포인터
스마트 포인터는 RAII (Resource acquisition is initialization)의 개념을 가장 잘 활용한 예 중의 하나다. RAII란 생성자에서 자원을 획득하고, 소멸자에서 자원을 자동적으로 파괴해야 한다는 원칙이다. <리스트 1>을 살펴보자. 할당한 메모리 ptr이, some\_condition인 경우는 해제되지 않고 리턴 하기 때문에 릭이 생긴다. 바보 같은 코드처럼 보이지만 할당된 자원이 많고, 함수가 복잡해질수록 이러한 일은 더욱 쉽게 일어난다. 이러한 문제점을 스마트 포인터를 사용해서 변경한 코드가 <리스트 2>다. <리스트 2>의 char\_ptr은 동작원리를 보여주기 위해서 간단하게 제작된 것이다. 실제 스마트 포인터의 구현은 훨씬 더 복잡하다. 하지만 걱정할 것 없다. 표준 라이브러이의 auto\_ptr이나 boost 라이브러리의 shared\_ptr과 같이 잘 구현된 스마트 포인터 클래스가 많이 있기 때문이다.
리스트 1 스마트 포인터를 사용하지 않은 코드
```cpp
void func()
{
char \*ptr = new char[20];
if(some\_condition)
return;
delete [] ptr;
}
```리스트 2 스마트 포인터를 사용한 코드
```cpp
class char\_ptr
{
private:
char \*m\_ptr;
public:
char\_ptr(size\_t size) { m\_ptr = new char[size]; }
~char\_ptr() { delete [] m\_ptr; }
operator char \*() { return m\_ptr; }
};
void func()
{
char\_ptr ptr(20);
if(some\_condition)
return;
}