본문 바로가기

Programming/C&CPP

new 사용시 예외 처리

반응형

new는 C++에서 객체의 메모리 할당과 생성자 호출을 통한 초기화를 담당합니다.

C의 malloc, calloc은 메모리 할당에 실패하게 되면 NULL을 리턴해줍니다.

하지만 new는 메모리 할당에 실패했을 때 NULL을 리턴하지 않습니다.

따라서 다음과 같이 예외 처리를 할 경우에는 정상적으로 동작하지 않습니다.

잘못된 코드

#include <iostream>
using namespace std;

void main()
{
	char* pData = new char[0x7FFFFFFF];
	if (nullptr == pData)
	{
		cout << "You can't reach here." << endl;
		return ;
	}

	delete[] pData;
}

C++ 표준에서 new는 메모리 할당에 실패했을 때 std::bad_alloc 예외를 발생하도록 되어 있습니다.

MFC 환경에서는 CMemoryException를 리턴합니다.

예외가 발생된다면 처리는 try, catch를 통해서 가능합니다.

위의 코드는 다음과 같은 형식으로 수정해서 사용해야 합니다.

1. try-catch를 활용한 예외 처리

#include <iostream>
using namespace std;

void main()
{
	char* pData = nullptr;
	try
	{
		pData = new char[0x7FFFFFFF];
	}
	catch (bad_alloc ex)
	{
		cout << ex.what() << endl;
		return ;
	}

	delete[] pData;
}

이제 정상적으로 실행이 가능합니다.

MFC 환경에서는 CMemoryException을 예외 처리하게 해줍니다.

Visual Assist X를 사용하시는 분들은 try만 쳐도 자동 완성을 통해서 예외 처리 구문을 작성해줍니다.

2. (std::nothrow)를 활용한 예외 처리

try-catch 구문이 번거롭게 느껴질 때는 new 뒤에 (std::nothrow)를 추가합니다.

(std::nothrow)가 추가될 경우 NULL을 리턴하는 기존의 방법으로 처리가 가능합니다.

다음과 같은 코드가 정상적으로 동작합니다.

#include <iostream>
using namespace std;

void main()
{
	char* pData = new (nothrow) char[0x7FFFFFFF];
	if (nullptr == pData)
	{
		cout << "You can reach here" << endl;
		return;
	}

	delete[] pData;
}

3. new handler

set_new_handler라는 함수를 통해서 예외를 던지기 전에 사용자가 정의한 동작을 수행할 수 있도록 할 수 있습니다.

set_new_handler는 <new> 헤더에 선언되어 있습니다.

리턴이 없고 인자가 없는 함수 포인터를 받아들입니다.

다음과 같이 예외 처리가 가능합니다.

#include <iostream>
#include <new>
using namespace std;

void MyFunc()
{
	cout << "Do Something..." << endl;

	set_new_handler(nullptr);
}

void main()
{
	set_new_handler(MyFunc);

	char* pData = nullptr;
	try
	{
		pData = new char[0x7FFFFFFF];
	}
	catch (bad_alloc ex)
	{
		cout << ex.what() << endl;
		return;
	}

	delete[] pData;
}

new는 메모리 할당에 실패할 경우 성공할 때까지 new를 반복해서 호출합니다.

set_new_handler로 설치한 처리자에서 set_new_handler(nullptr)을 호출하지 않으면

메모리 할당에 성공할 때까지 무한히 호출되기 때문에 내부에서 처리를 해줘야 합니다.

Effective C++에서는 set_new_handler로 설치한 처리자에서 다음과 같은 방법 중 하나를 선택하라고 합니다.

1. 사용할 수 있는 메모리를 더 많이 확보하라.
2. 다른 new 처리자를 설치하라.(위와 비슷한 방법이지만 MyFunc() 안에서 다른 new 처리자를 설치합니다.)
3. new 처리자의 설치를 제거하라.(위와 같은 방법입니다.)
4. 예외를 던져라.
5. abort()나 exit()를 호출해서 강제 종료하라.

C++의 new를 사용해서 메모리를 할당할 때는 위의 방법을 참고해서 예외처리를 진행하면 됩니다.




반응형