신입 게임 개발자의 프로그래밍 일기
[C++ 입문자에서 벗어나기]Chapter_4: 메모리(Memory)#2 본문
[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"에 대한 이야기는 이쯤으로 마치겠습니다.
많이 부족한 포스팅이지만 부족한 현재의 작성자 모습으로는 이 정도가 한계인 것 같습니다.
'Language > C++' 카테고리의 다른 글
[C++ 입문자에서 벗어나기]Chapter_4: 메모리(Memory)#4 - 1 (0) | 2018.01.27 |
---|---|
[C++ 입문자에서 벗어나기]Chapter_4: 메모리(Memory)#3 (0) | 2018.01.26 |
[C++ 입문자에서 벗어나기]Chapter_4: 메모리(Memory)#1 (5) | 2017.12.11 |
ISO Cpp 게시글 Memory Management와 관련된 여러 질문들 (0) | 2017.12.11 |
[C++ 입문자에서 벗어나기]Chapter_3: 빌드(Build)#2 (0) | 2017.12.01 |