C++에서 new 연산자는 동적 메모리 할당을 담당하며, 할당된 변수는 힙(heap) 영역에 배치됩니다. 반대로 delete[] 연산자는 배열 형태로 할당된 이 메모리를 힙에서 해제하는 역할을 합니다.
그렇다면 delete[]는 자신이 해제해야 할 배열의 크기를 어떻게 알 수 있을까요? 핵심은 new[]가 메모리를 할당할 때 실제 배열 본체 앞에 별도의 관리 영역(오버헤드, 흔히 쿠키(cookie)라고 부름)을 추가로 확보하고, 그곳에 생성한 요소의 개수를 기록해 둔다는 점입니다. delete[]는 이 개수 정보를 읽어 각 요소의 소멸자를 정확한 횟수만큼 호출한 뒤 전체 메모리를 해제합니다. 덕분에 프로그래머가 배열 크기를 직접 넘겨 주지 않아도 안전하게 해제할 수 있습니다.
단, new와 delete[], new[]와 delete는 반드시 짝을 맞춰 사용해야 합니다. 짝이 어긋나면 미정의 동작(undefined behavior)이 발생할 수 있습니다.
예제 코드
#include <iostream>
using namespace std;
int main() {
int B = 4;
int A = 5;
int** a = new int*[B];
for(int i = 0; i < B; ++i)
a[i] = new int[A];
for(int i = 0; i < B; ++i)
for(int j = 0; j < A; ++j)
a[i][j] = i;
for(int i = 0; i < B; ++i)
for(int j = 0; j < A; ++j)
cout << a[i][j] << endl;
for(int i = 0; i < B; ++i)
delete [] a[i];
delete [] a;
return 0;
}위 예제는 4행 × 5열 크기의 2차원 배열을 동적으로 생성하고, 각 행의 인덱스 값으로 초기화한 뒤 출력하는 프로그램입니다. 해제 시에는 먼저 행(row) 개수만큼 각 행을 delete[]로 해제한 후, 마지막에 포인터 배열 자체를 delete[]로 해제해야 메모리 누수 없이 깔끔하게 정리됩니다.
실행 결과
0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3