[C++] 항목 16: new 및 delete를 사용할 때는 형태를 반드시 맞추자

업데이트:     Updated:

카테고리:

태그:

이 글은 아래의 책을 자세히 정리한 후, 정리한 글을 GPT에게 요약을 요청하여 작성되었습니다.
이펙티브 C++ 제3판, 스콧 마이어스 저자, 곽용재 번역

📦 3. 자원 관리

👉🏻 항목 16: new 및 delete를 사용할 때는 형태를 반드시 맞추자

동적 할당 시 new를 사용하고, 해제할 때는 delete를 사용한다.
하지만 배열을 할당했다면 delete[]로 해제해야 한다.

string *stringArray = new string[100];
...
delete stringArray;  // ❌ 잘못된 코드

위 코드는 new[]로 배열을 할당했음에도 불구하고, delete로 단일 객체 삭제를 시도하고 있다.

이런 경우, 첫 번째 객체만 소멸되고, 나머지 객체들의 소멸자는 호출되지 않아서
정의되지 않은 동작이 발생할 수 있다.


✅ 배열의 메모리 구조는 단일 객체와 다르다

배열을 할당하면, 런타임에서 배열의 크기 정보도 함께 저장된다.
이 정보는 delete[]가 호출될 때 각 원소의 소멸자를 정확히 호출하기 위해 필요하다.

  • 배열 구조 예시:

    | 배열 크기 n | 객체 1 | 객체 2 | … | | ——- | —- | —- | — |

  • 단일 객체 구조 예시:

    | 객체 1 | | —- |

따라서 deletedelete[]는 내부 동작이 완전히 다르며, 서로 교차해서 사용하면 안 된다.


✅ new와 delete는 반드시 형태를 맞춰야 한다

string *stringPtr1 = new string;
string *stringPtr2 = new string[100];

delete stringPtr1;     // ✅ 단일 객체 삭제
delete [] stringPtr2;  // ✅ 배열 삭제
  • new[]를 사용했다면, delete에도 반드시 []를 붙여야 한다.
  • new[]를 사용하지 않았다면, delete[]도 사용해서는 안 된다.

→ 짝을 정확히 맞추지 않으면 정의되지 않은 동작이 발생할 수 있다.


⚠️ typedef로 인해 배열이라는 사실이 감춰질 수 있다

// AddressLines == string[4]
typedef string AddressLines[4];

// string *pal = new string[4];
string *pal = new AddressLines;

delete pal;     // ❌ 단일 객체 삭제
delete [] pal;  // ✅ 배열 삭제

typedef를 통해 배열 타입을 감추면, 포인터가 배열을 가리킨다는 사실을 놓치기 쉽다.
이로 인해 deletedelete[]를 혼동할 위험이 커진다.

배열 타입을 typedef로 감추는 것은 피하는 것이 좋다.


✅ 안전한 대안: vector 사용

std::vectorstd::array와 같은 컨테이너를 사용하면 이러한 실수를 방지할 수 있다.

vector<string> pal(4);
  • 메모리 해제는 자동으로 이루어지고
  • 생성자/소멸자 호출도 자동
  • 타입도 명확하게 드러나서 실수할 일이 없다

직관적이고 안전한 대안이다.


🧐 정리

  1. new[]로 할당한 메모리는 반드시 delete[]로 해제해야 한다
  2. newdelete는 형태를 정확히 맞춰 써야 한다 (단일 vs 배열)
  3. 배열 타입을 typedef로 감추면 실수하기 쉬우므로 지양하자
  4. 가능하면 vectorarray 같은 컨테이너를 사용하는 것이 가장 안전하다

Cpp 카테고리 내 다른 글 보러가기

댓글남기기