강께르의 개발일지

[C++] delete와 delete[] 본문

프로그래밍/C++

[C++] delete와 delete[]

강께르 2021. 6. 13. 18:09

 이 글은 C++에서 제공하는 delete와 delete[]의 차이점을 조사하고 익히기 위해 작성하였다.

 

1. new와 delete

- C에서 동적할당을 위해 malloc을 사용했었고 할당에 대한 해제 및 소멸을 위해 free를 썼었다.

- C++에서는 새롭게 new와 delete를 제공한다.

int* ptr = new int; // 동적 할당
delete ptr; // 해제 및 소멸

 

2. delete와 delete[]

- delete는 단일 객체로 할당된 메모리를 해제하는 역할을 맡고 있다. 1.에서 적은 코드와 같이 배열이 아닌 단일 객체에 대해서 메모리를 해제한다.

- delete[]는 배열로 할당된 메모리를 해제하는 역할을 맡고 있다. 배열로 할당된 각각의 요소의 메모리가 해제된다.

 

3. 의문점 제기

- 그런데 delete[]를 굳이 쓰는 이유가 무엇인가? delete로 해제하면 단일 객체인 '배열 하나'의 메모리가 해제될 것이지 않은가?

- 만약 delete로 해제하는 예를 생각해보자. 여기 int형 메모리 공간 5개가 필요한 배열 Array가 있다고 하자.

- Array는 프로그램에 끝에 와서 그 사용을 마치고 메모리를 환원 혹 해제하려고 delete[]가 아닌 delete를 사용하려고 한다.

- delete Array;가 수행되는데 배열의 특징 중 하나인 배열의 이름은 그 배열의 첫 주소를 반환한다고 한다.

- 그렇다면 우리가 기대하고 있는 모든 배열 인덱스의 메모리 해제라는 결과는 커녕 첫 주소 딱 하나만 해제하게 될 것이다.

- 만약 delete[] Array;를 사용한다면 int형 메모리 공간 5개를 처음부터 끝까지 해제하게 될 것이다.

 

4. new 연산자의 특별한 점, delete[]가 가능한 이유

- 하지만 특별한 인덱스 정보 없이 어떻게 delete[]가 가능한 것인가? 보통 프로그래밍을 하다보면 특정 인덱스를 알려주지 않으면 원하는 끝 인덱스보다 이상으로 읽어들이거나 수정하게 되어 메모리 관련 오류를 쉽게 볼 수 있다.

- new에는 메모리 할당 시 배열 크기에 대한 정보로 4바이트만큼 메모리를 더 할당한다고 한다. 만약 int형 4바이트를 2개만큼 배열을 할당한다면 8바이트가 아니라 12바이트를 할당한다는 것이다.

- 그래서 delete[]를 사용하면 이 값을 확인하여 해제한다.

 

2021-06-15_추가)

- 어제 1대3 몬스터 턴제 전투 게임을 개발하면서 알아낸 것이다. 알아내기 전까지 머리 싸매고 해결해보려 했지만, 이해되지 않은 상태에서 수정만 하고 결과가 돼서 냅뒀는데 아마도 아래와 같은 점 때문에 되지 않은 것 같았다.

- 그 상황은 아래 코드와 같다.

class MainGame
{
private:
	Player* player;
	Monster* monster[3];
	int m_key;
public:
    ...
}

MainGame::MainGame() : m_key(0)
{
	player = new Player(50, 30, 15, 10, 30, 10, "전사");
	int randNum;
	srand((unsigned int)time(NULL));
	for (int i = 0; i < 3; i++)
	{
		randNum = rand() % 100;
		if(randNum < 50)
			monster[i] = new Monster(30, 20, 2, 10, 10, 10, "하피");
		else
			monster[i] = new Monster(50, 20, 4, 10, 10, 10, "큰턱괴물");
	}
}

...

MainGame::~MainGame()
{
	delete player;
    // delete[] monster;        // 이 부분에서 힙 영역에 대한 오류 발생!!
	for(int i = 0; i < 3; i++)
		delete monster[i];
}

- MainGame 클래스는 Monster 포인터 변수를 세 개의 인덱스를 지니도록 배열로 선언한 상태이다.

- 생성자를 통해 초기화를 하면, 무작위의 몬스터가 선택되어 정보가 대입될 수 있도록 반복문과 조건문을 이용해 배열 인덱스마다 동적할당으로 Monster 객체를 생성한다.

- 프로그램 종료 시, 자동으로 호출되는 생성자에서 moster 배열 변수를 메모리 해제하려고 했는데! 배우기로는 동적할당 받은 배열 변수는 delete[]를 사용하는 줄 알았다.

- 하지만 힙 영역에 대한 메모리 오류가 났었고 그 이유를 이제야 생각해보니 동적할당할 때, new Monster[3]과 같은 방법으로 배열로 동적할당하는 것이 아니라 단일 객체 생성 동적 할당을 해서 그런 것 같다.

- 옛날에 적었던 위의 내용을 참고해서 오류를 분석하면 new ~[]로 동적할당하는 것은 인덱스만큼의 동적할당을 하고 4바이트만큼 배열 크기에 대한 정보를 할당한다. 그냥 new ~로 동적할당한다면 인덱스마다 동적할당은 무리없이 할 수 있어도 배열크기에 대한 정보를 할당하지 않기 때문에, 나중에 소멸자로 delete[]를 사용하지만 배열 크기를 알 수 없다. 그러면 delete[]는 배열의 끝을 알 수 없어서 정상적인 메모리 해제를 할 수 없다. 그래서 delete와 delete[]를 구분해서 사용방법을 잘 알아야겠다.

- 만약 힙 영역 오류가 생긴다면 내가 동적할당을 어떻게 했는지 확인해볼 필요가 있다는 것을 배웠다.