본문으로 건너뛰기
모던 C++ 심화LESSON 05

동적 할당의 문제: new·delete, 메모리 누수, 이중 해제

난이도중급 → 심화
예상 시간70분
선수지식이전 강의

5강. 동적 할당의 문제: new·delete, 메모리 누수, 이중 해제

이번 강의에서 해결할 문제​

new로 만든 객체는 정상 경로뿐 아니라 조기 반환과 예외 경로에서도 정확히 한 번 정리되어야 합니다. 코드가 커질수록 수동 delete를 모든 경로에 맞추기 어렵고, 복사된 주소 때문에 누수나 이중 해제가 생깁니다.

학습 목표​

먼저 알아야 할 핵심 개념​

new T는 동적 저장 기간의 T 객체를 만들고 주소를 반환합니다. 대응하는 delete는 객체의 소멸자를 호출하고 저장소를 반납합니다. 배열 new[]에는 delete[]가 필요하지만, 현대 C++ 애플리케이션에서는 직접 맞추기보다 vector, string, unique_ptr 같은 RAII 타입을 우선합니다.

왜 이 문제가 위험한가​

다음 위험 코드는 실행하지 않아도 제어 흐름만으로 문제를 찾을 수 있습니다.

review_only_bad_allocation.cpp
Task* loadTask(bool valid) {
Task* task = new Task{"build", 2};
if (!valid) return nullptr; // task를 잃어버려 누수
return task; // 누가 delete할지 시그니처에 없음
}

void doubleOwner(Task* task) {
Task* alias = task;
delete task;
delete alias; // 같은 객체를 두 번 정리: UB
}

nullptr로 바꾸는 습관만으로는 복사된 alias를 고칠 수 없습니다. 소유자가 정확히 한 곳이 되도록 타입과 구조를 바꿔야 합니다.

가장 작은 예제로 시작하기​

safe_factory.cpp
#include <iostream>
#include <memory>
#include <string>
#include <utility>

struct Task {
std::string name;
int priority{};
};

std::unique_ptr<Task> makeTask(std::string name, int priority) {
if (name.empty() || priority < 0) return nullptr;
return std::make_unique<Task>(Task{std::move(name), priority});
}

int main() {
auto task = makeTask("build", 2);
if (task) std::cout << task->name << ':' << task->priority << '\n';
}

코드 한 줄씩 이해하기​

  1. 반환 타입 unique_ptr<Task>가 성공 시 단일 소유권이 호출자로 이동함을 나타냅니다.
  2. 유효하지 않은 입력은 객체를 만들기 전에 nullptr 결과로 종료합니다.
  3. make_unique는 생성과 소유 포인터 구성을 한 표현으로 묶습니다.
  4. task가 main을 벗어나면 Task가 정확히 한 번 파괴됩니다.
  5. 수동 delete가 없어 조기 반환 경로도 같은 정리 규칙을 따릅니다.

실행 결과와 메모리·동작 흐름​

유효한 입력에서는 Task가 동적으로 생성되고 main의 task가 유일한 소유자가 됩니다. build:2를 출력한 뒤 스코프 종료 시 자동 정리됩니다. 빈 이름이면 동적 객체 자체가 만들어지지 않습니다.

단계별 실습​

흔한 실수와 해결 방법​

언제 사용하고 언제 피할까​

런타임에 구체 타입이 정해지는 다형 객체나 명시적인 독립 수명이 필요하면 RAII 기반 동적 소유를 사용합니다. 크기와 수명이 명확한 값, 컨테이너가 직접 보관할 수 있는 객체에는 수동 동적 할당을 피합니다.

게임 개발 연결​

많은 객체를 반복 생성하는 코드에서 누수는 시간이 지날수록 커집니다. 먼저 객체를 값으로 둘 수 있는지 검토하고, 동적 수명이 필요할 때만 소유자를 한 곳으로 정합니다.

이해 점검 질문 3개​

  1. raw pointer 반환이 삭제 책임을 명확히 전달하지 못하는 이유는 무엇인가요?
  2. 조기 반환이 수동 new 코드에서 누수를 만들기 쉬운 이유는 무엇인가요?
  3. 동적 할당 대신 vector<Task> 값 저장이 더 적합한 사례는 무엇인가요?

핵심 요약​

다음 강의 연결​

6강. RAII에서 메모리뿐 아니라 파일과 잠금 자원도 객체 수명으로 정리합니다.

MINI QUIZ

동적 할당의 문제: new·delete, 메모리 누수, 이중 해제 미니 퀴즈

선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.

0 / 2
  1. 문제 1“동적 할당의 문제: new·delete, 메모리 누수, 이중 해제” 실습 결과를 확인할 때 적용해야 할 설명은 무엇인가요?
  2. 문제 2“동적 할당의 문제: new·delete, 메모리 누수, 이중 해제” 실습 중 ‘모든 new 뒤에 바로 delete를 쓰면 된다고 생각’ 상황을 발견했습니다. 본문과 일치하는 설명은 무엇인가요?
LESSON STATUS

학습을 마쳤나요?

직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.

5강. 동적 할당의 문제: new·delete, 메모리 누수, 이중 해제 미완료 상태