1
2
3
4
5
std::string* stringArray = new std::string[100];
 
...
 
delete stringArray;
cs

 

위 코드를 보면 stringArray가 가리키는 100개의 string 객체들 가운데 99개는 정상적인 소멸 과정을 거치지 못할 것이다.

 

객체 배열 해제 시에는 []delete를 해야만 하는 이유를 알아보자.

 

new 연사자를 사용하면 다음과 같은 2가지 내부 동작을 진행한다.


 1. 메모리 할당. (operator new라는 이름의 함수가 쓰임.)
 2. 할당된 메모리에 대해 한 개 이상의 생성자가 호출.

 

이와 마찬가지로 delete 연산자를 사용하면 2가지 내부 동작을 진행한다.

 

 1. 할당된 메모리에 대해 한 개 이상의 소멸자가 호출.
 2. 메모리 해제. (operator delete라는 이름의 함수가 쓰임.)

 

여기서 단일 객체를 new / delete 하는 경우와 객체 배열을 new/delete 하는 경우의 메모리 배치구조는 서로 다르다.

 

단일 객체의 힙 메모리 배치 구조.

 

Object

           

 

객체 배열의 힙 메모리 배치 구조.

 

6

Object

Object 

Object 

Object 

Object 

Object 

 

상기와 같이 대다수의 컴파일러의 경우에는 객체 배열이 힙 메모리에 할당되면 맨 앞에 배열의 크기 정보가 함께 배치된다.

이 때문에, delete 연산자는 소멸자가 몇 번 호출될지를 쉽게 알 수 있게된다.

즉, []delete는 앞쪽의 배열 크기를 읽고, 배열 크기에 해당하는 횟수만큼 소멸자를 호출하게 된다.


만약 delete를 사용하게되면 그냥 단일 객체라 간주하고 소멸자 호출 횟수가 부족해져 메모리 누수가 발생할 것이다.

 

 

1
2
3
std::string stringObjec = new std::string//단일 객체.
 
[]delete stringObjec; //단일 객체를 []delete로 해제.
cs

 

반대로 위와 같이 단일 객체를 해제하려고 할 때, []delete 연산자를 사용한다면... []delete 연산자는 stringObject 객체 메모리 앞쪽의

몇 바이트를 읽어 배열 크기라고 해석할 것이다. 그리고 배열 크기만큼 소멸자를 호출할텐데 결국 엉뚱한 메모리를 해제하려 할테고

알 수 없는 동작이 진행될 것이다.

 

그러므로 new 연산자에 []를 썼으면, delete 연산자에도 []를 써야 한다는 간단한 규칙만 생각해두면 된다.

 

 

1
2
3
4
5
6
7
typedef std::string stringArray[4];
 
std::string *pa1 = new stringArray; //new stringArray이 new string[4]라는 점을 잊으면 안된다.
 
...
 
delete[] pa1;
cs

 

또한 typedef로 정의된 어떤 타입의 배열을 생성하려고 new를 썼다면 delete 또한 []를 잊지 말아야 한다.

위의 예제와 같이 typedef를 사용한 경우도 결국 배열이다.
그러나 저렇게 배열 타입이 눈에 명확하게 보이지 않기 때문에, 배열 타입을 typedef 타입으로 만들지 않는 것이 좋다.

 

1줄 요약


 - new 표현식에 []를 썼으면, 대응되는 delete 표현식에도 []를 쓰자.
   마찬가지로 new 표현식에 []를 안 썼으면, 대응되는 delete 표현식에도 []를 쓰지 말자.

+ Recent posts