신입 게임 개발자의 프로그래밍 일기

[C++ 입문자에서 벗어나기]Chapter_4: 메모리(Memory)#2 본문

Language/C++

[C++ 입문자에서 벗어나기]Chapter_4: 메모리(Memory)#2

KFGD 2018. 1. 9. 11:21

[C++ 입문자에서 벗어나기]Chapter_4: 메모리(Memory)#2


2018년에 작성하는 첫 포스팅입니다.

이번 포스팅에서는 new와 관련된 활용에 대해 이야기해보겠습니다.

먼저 new의 Syntax를 살펴봅시다!


void* operator new(std::size_t count) throw(bad_alloc);

void* operator new(std::size_t count,
    const std::nothrow_t&) throw();

void* operator new(std::size_t count,
    void* ptr) throw();

<참고: Microsoft Developer Network의 <new> operator 글>


맨 처음 new는 일반적으로 가장 많이 사용하는 new의 형태입니다.

두번째 new는 책(C++기초 플러스 5판, Effective C++ 3판)에서위치 지정 new라고 번역된 placement new입니다.

마지막 세번째는 new는 메모리 할당 실패 시, bad_alloc이라는 예외를 던지지 않고 null을 반환하는 nothrow new입니다.

첫번째 new만 익숙하시고 나머지 new들은 생소하실 겁니다.(저도 생소합니다.)

우선 익숙한 첫번째 new를 이야기해보고 나머지 낯선 new들을 파헤쳐보겠습니다.


[std::bad_alloc이라는 예외를 던지는 일반적인 new]


지금까지 써왔던 친숙한 new라고 생각했는데 갑자기 std::bad_alloc이라는 예외는 또 무엇입니까? 라는 분들도 계실겁니다.

이 게시글을 작성하는 저도 new로 메모리 할당 과정에서 예외가 발생한 적은 경험해본 적이 없음을 실토합니다.

그래서 이것에 대해서 이론적인 이야기와 간략한 사용방법만 살펴보려고 합니다.


한번 메모리 할당 에러를 발생시켜보겠습니다.


<소스 코드>


<결과>

 


매우 큰 int 배열을 만들었습니다.

크기는 "그냥 대충 이정도 에러가 발생하겠지?" 정도로 만들었으니 개수에 대한 이야기는 넘어가겠습니다.

실행을 시키니 new 함수의 기본 handler는 bad_alloc이라는 예외를 던졌고 소스코드에 예외 발생을 대비한

try-catch문이 없음으로 이 프로그램은 강제 종료됨을 확인할 수 있습니다. 

바로 try-catch문을 사용하여 에러를 잡을 수 있지만 추가적인 방법이 있습니다.

그것은 new_handler(new 처리자 함수) 입니다.

new_handler를 통해서 new가 메모리 할당 실패시, std::bad_alloc이라는 예외를 던지기 전에 처리 루틴을 추가시킬 수 있습니다.

이게 무슨 소리인지 간단한 코드로 직접 테스트해보겠습니다.


<소스 코드>


<결과>

 


new_handler를 통해서 new 메모리 할당을 처리하고 예외를 발생시키는 것을 확인할 수 있습니다.

위 코드의 handler 함수 코드에서 추측 할 수 있겠지만 new_handler라는 타입과 set_new_handler의 syntax를 살펴보겠습니다.


new_handler set_new_handler(new_handler _Pnew) throw();

<참고: Microsoft Developer Network의 <new>함수</new> 글>


typedef void (*new_handler)();

<참고: Microsoft Developer Network의 <new>형식 정의</new> 글>


new_handler는 단순히 void 타입의 함수 포인터를 재정의한 것임을 확인할 수 있으며

set_new_handler는 void 타입의 함수를 handler로 사용할 수 있음을 알 수 있습니다.

그리고 제일 첫번째 set_new_handler 함수가 반환하는 new_handler를 임시 저장하는 것을 소스 코드 상에서

확인할 수 있는데 이는 바꾸기 전 기본 handler 함수를 저장해 놓고 나중에 new를 활용한 메모리 할당을 마치고

본래의 기본 handler함수로 복귀시키기 위함입니다.

new_handler도 알아봤으니 이제 try-catch를 통해서 프로그램 강제 종료를 막아보겠습니다.


<소스 코드>


<결과>

 


이 소스 코드는 크기를 줄여가면서 메모리 할당을 재시도하여 될때까지 반복시키는 코드입니다.

try-catch로 std::bad_alloc 예외를 방지하여 프로그램의 강제 종료를 막고 정상적으로 적당한(?) 크기의

메모리 할당이 이루어짐을 확인할 수 있습니다.


[Effective C++에서 이야기하는 융통성있는 handler 만들기]


이 게시글에는 set_new_handler로 설정한 handler함수가 전부 std::bad_alloc이라는 예외를 던지도록 작성되었지만

그 이외의 것도 상관이 없습니다.

다만 Effective C++가 제시하는 융통성있는 handler 함수 설계는 아래와 같습니다.


1. 사용할 수 있는 메모리를 더 많이 확보합니다.

=>개인 소견: Memory Pool과 같은 형태의 메모리 관리 기법을 사용하고 있다면 

    handler에서 불필요한 메모리를 Pool에서 없애는 형태로 코드를 작성해면 될 것 같습니다. 


2. 다른 new 처리자를 설치합니다.

=>개인 소견: 현재의 handler로 new 메모리 할당 처리가 불가능할 경우 

    다시 set_new_handler를 호출하여 다른 handler로 new 메모리 할당 처리를 할 수 있도록 하라는 것 같습니다.


3. new 처리자의 설치를 제거합니다.

=>개인 소견: set_new_handler에 null pointer를 넘겨서 new 처리자 함수를 제거시키면 

   operator new는 메모리 할당이 실패했을 때 예외를 던지다고 합니다...


4. 예외를 던집니다.

=>개인 소견: bad_alloc 또는 이로부터 파생된 타입의 예외를 던질 수 있으니

    try-catch의 catch문에서 예외의 종류에 맞게 Log를 남기면 될 거 같습니다.


5. 복귀하지 않습니다.

=>개인 소견: abort나 exit 함수를 호출하여 그냥 프로그램 강제종료시키라는 이야기입니다.



"bad_alloc이라는 예외를 던지는 일반적인 new"에 대한 이야기는 이쯤으로 마치겠습니다.

많이 부족한 포스팅이지만 부족한 현재의 작성자 모습으로는 이 정도가 한계인 것 같습니다.

Comments