[C++][Effective C++] 항목 49 : new 처리자의 동작 원리를 제대로 이해하자 (상)

WestCoast·2022년 5월 9일
0

C, C++

목록 보기
11/12

1. 컴파일러 기본 예외처리


#include <iostream>
using namespace std;

#define SIZE 499999999L

int main()
{
    try
    {
        int *arr = new int[SIZE];
        cout << "메모리 할당 성공" << endl;
    }
    catch (std::exception ex)
    {
        cout << ex.what() << endl;
    }
}
  • try에서 동적 메모리에 할당하려는 배열의 SIZE가 너무 크기 때문에 예외를 던진다.
  • catch에서 bad allocation 예외를 출력한다.

출력

bad allocation

2. 에러 처리 함수 new 처리자


#define SIZE 499999999L

void OutOfMem()
{
    cerr << "메모리 할당 실패" << endl;
    std::abort(); // 프로그램 종료
}

int main()
{
    try
    {
        // OutOfMem : 요구된 메모리를 new 연산자가 할당하지 못했을 때
        // 호출될 사용자 정의 함수
        // new 처리자(new-handler)라고 부른다.
        set_new_handler(OutOfMem);
        int *arr = new int[SIZE];
        cout << "메모리 할당 성공" << endl;
    }
    catch (std::exception ex)
    {
        cout << ex.what() << endl;
    }
}
  • set_new_handler 에 사용자 정의 new_handler 함수(여기서는 OutOfMem)를 넣어주면 operator new 가 예외를 던지기 전에 우리가 설정한 에러 처리 함수를 우선적으로 호출할 수 있다.

출력


3. 에러 처리 함수에서 또 예외가 발생하게 된다면?


#define SIZE 499999999L

void OutOfMem()
{
    cerr << "메모리 할당 실패 처리 시작" << endl;
    int *arr = new int[SIZE]; // 메모리 확보에 실패한다.
    cerr << "메모리 할당 실패 처리 종료" << endl;
    std::abort(); // 프로그램 종료
}

int main()
{
    try
    {
        set_new_handler(OutOfMem);
        int *arr = new int[SIZE];
        cout << "메모리 할당 성공" << endl;
    }
    catch (std::exception ex)
    {
        cout << ex.what() << endl;
    }
}
  • new 연산자가 메모리 할당에 실패하면 OutOfMem을 호출하게 되고 OutOfMem 안의 new 연산자가 메모리 할당에 실패하면 OutOfMem을 호출하게 되고 그 OutOfMem의 new 연산자가 메모리 할당에 실패하게 되면... 반복

출력


4. new 처리자 함수를 설계할 때 반드시 지켜야 할 점


아래 5가지 동작 중 하나를 꼭 해주어야 한다.

  • 사용할 수 있는 메모리를 더 많이 확보합니다.
  • 다른 new 처리자를 설치합니다.
  • new 처리자의 설치를 제거합니다.
  • 예외를 던집니다.
  • 복귀하지 않습니다.

하나씩 살펴보자.


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


#include <iostream>
using namespace std;

#define SIZE 499999999L

// 1. 프로그램이 시작할 때 메모리 블록을 크게 하나 할당한다.
int badAllocArr[1000];
void OutOfMem()
{
    cerr << "메모리 할당 실패 처리 시작" << endl;
    // 2. new 처리자가 할당해놨던 메모리를 쓸 수 있도록 구현.
    int *arr = badAllocArr;
    cerr << "메모리 할당 실패 처리 종료" << endl;
    std::abort(); // 프로그램 종료
}

int main()
{
    try
    {
        set_new_handler(OutOfMem);
        int *arr = new int[SIZE];
        cout << "메모리 할당 성공" << endl;
    }
    catch (std::exception ex)
    {
        cout << ex.what() << endl;
    }
}

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


#include <iostream>
using namespace std;

#define SIZE 499999999L

// 1. OutOfMem이 가용 메모리 확보에 실패했을 때 호출될 또 다른 new 처리자
void OutOfMemSecond()
{
    cerr << "Second: 메모리 할당 실패" << endl;
    std::abort();
}

void OutOfMem()
{
    cerr << "메모리 할당 실패 처리 시작" << endl;
    // 2. 대신 처리해줄 new 처리자를 설치한다.
    set_new_handler(OutOfMemSecond);
    int *arr = new int[SIZE];
    cerr << "메모리 할당 실패 처리 종료" << endl;
    std::abort(); // 프로그램 종료
}

int main()
{
    try
    {
        set_new_handler(OutOfMem);
        int *arr = new int[SIZE];
        cout << "메모리 할당 성공" << endl;
    }
    catch (std::exception ex)
    {
        cout << ex.what() << endl;
    }
}

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


#include <iostream>
using namespace std;

#define SIZE 499999999L

void OutOfMem()
{
    cerr << "메모리 할당 실패 처리 시작" << endl;
    set_new_handler(nullptr); // new 처리자를 nullptr로 설정한다.
    int *arr = new int[SIZE]; // 메모리 확보에 실패하고 예외를 던진다.
    cerr << "메모리 할당 실패 처리 종료" << endl;
    std::abort(); // 프로그램 종료
}

int main()
{
    try
    {
        set_new_handler(OutOfMem);
        int *arr = new int[SIZE];
        cout << "메모리 할당 성공" << endl;
    }
    catch (std::exception ex) // 예외를 받는다.
    {
        cout << ex.what() << endl;
    }
}

4-4. 예외를 던집니다.


#include <iostream>
using namespace std;

#define SIZE 499999999L

void OutOfMem()
{
    cerr << "메모리 할당 실패" << endl;
    throw bad_alloc();  // 예외를 던진다.
}

int main()
{
    try
    {
        set_new_handler(OutOfMem);
        int *arr = new int[SIZE];
        cout << "메모리 할당 성공" << endl;
    }
    catch (std::exception ex) // 예외를 받는다.
    {
        cout << ex.what() << endl;
    }
}

4-5. 복귀하지 않습니다.


#include <iostream>
using namespace std;

#define SIZE 499999999L

void OutOfMem()
{
    cerr << "메모리 할당 실패" << endl;
    std::abort(); // 프로그램 종료
}

int main()
{
    try
    {
        set_new_handler(OutOfMem);
        int *arr = new int[SIZE];
        cout << "메모리 할당 성공" << endl;
    }
    catch (std::exception ex)
    {
        cout << ex.what() << endl;
    }
}

profile
게임... 만들지 않겠는가..

0개의 댓글