내배캠 TIL

[내배캠 TIL 260105] C++ 일반 포인터와 Unique_ptr

xodn246 2026. 1. 5. 20:56

C++ 캐릭터 인벤토리 구현에서

일반 포인터와 unique_ptr의 차이점

캐릭터 인벤토리를 구현하면서 아이템을 어떤 방식으로 관리할지 고민했다.
가장 단순한 방법은 아이템을 동적 할당한 뒤 일반 포인터(Item*)를 벡터에 저장하는 방식이다.
하지만 C++에서는 이 방식이 여러 가지 위험을 동반한다.
이를 해결하기 위한 대안으로 std::unique_ptr을 사용한 인벤토리 구조를 비교해보았다.


1. 일반 포인터를 사용한 인벤토리

일반 포인터를 사용한 인벤토리는 다음과 같은 형태가 된다.

std::vector<Item*> inventory;

 

아이템을 획득할 때는 new로 동적 할당한 뒤 벡터에 추가한다.

inventory.push_back(new HealthPotion());

 

아이템을 사용할 때는 직접 delete를 호출하고 벡터에서 제거해야 한다.

delete inventory[i]; inventory.erase(inventory.begin() + i);

장점

  • 구조가 단순하고 이해하기 쉽다.
  • C 스타일 메모리 관리에 익숙하다면 빠르게 구현할 수 있다.

단점

  • 메모리 해제를 직접 관리해야 한다.
  • delete를 빼먹으면 메모리 누수가 발생한다.
  • 이미 삭제한 포인터를 다시 삭제하는 이중 해제 위험이 있다.
  • 아이템을 언제, 어디서 삭제해야 하는지 코드 전체를 따라가야 알 수 있다.

즉, **“이 포인터를 누가 소유하고 있는가”**가 코드상에 명확히 드러나지 않는다.
프로젝트 규모가 커질수록 유지보수가 어려워진다.


2. unique_ptr을 사용한 인벤토리

같은 인벤토리를 std::unique_ptr로 구현하면 구조가 달라진다.

std::vector<std::unique_ptr<Item>> inventory;

아이템을 추가할 때는 소유권을 이동시킨다.

inventory.push_back(std::make_unique<HealthPotion>());
아이템을 사용할 때는 delete를 호출하지 않는다.
inventory.erase(it); // 자동으로 메모리 해제

핵심 개념

unique_ptr은 단 하나의 소유자만 가질 수 있는 포인터이다.
복사가 금지되어 있으며, 반드시 이동(std::move)으로만 전달된다.

이로 인해 아이템의 소유권이 Player에게 명확히 귀속된다는 점이 코드로 표현된다.


3. unique_ptr이 더 유리한 이유

1. 메모리 관리 자동화

unique_ptr은 스코프를 벗어나거나 컨테이너에서 제거되는 순간 자동으로 메모리를 해제한다.
delete를 직접 호출할 필요가 없다.

 

2. 이중 해제 원천 차단

unique_ptr은 복사가 불가능하다.
같은 객체를 두 곳에서 동시에 소유하는 상황 자체가 컴파일 단계에서 차단된다.

 

3. 소유권이 코드에 드러난다

std::vector<std::unique_ptr<Item>> inventory;

이 한 줄만 봐도
“아이템은 Player가 단독으로 소유한다”는 의도가 명확해진다.

 

4. 소멸자 코드가 단순해진다

일반 포인터 방식에서는 소멸자에서 반복적으로 delete를 호출해야 한다.
unique_ptr을 사용하면 소멸자를 비워두거나 = default로 처리할 수 있다.


4. 언제 일반 포인터를 쓰고, 언제 unique_ptr을 써야 하는가

일반 포인터는 소유권이 없는 경우에만 사용하는 것이 바람직하다.

void Player::Attack(Monster* monster);

이 경우 Player는 Monster를 소유하지 않고 참조만 한다.

반면, 인벤토리처럼

  • 객체의 생명주기를 관리해야 하고
  • 컨테이너에 장기간 보관하며
  • 삭제 책임이 명확해야 하는 경우

에는 unique_ptr이 훨씬 안전하고 명확한 선택이다.


5. 결론

캐릭터 인벤토리는 아이템의 생성부터 삭제까지 생명주기를 책임지는 구조이다.
이런 구조에서 일반 포인터를 사용하는 것은 구현은 쉽지만 유지보수 비용이 크다.

std::unique_ptr을 사용하면

  • 메모리 안전성이 높아지고
  • 소유권이 명확해지며
  • 코드의 의도가 분명해진다.

결과적으로 인벤토리 구현에서는 unique_ptr을 사용하는 방식이 더 유리하다고 판단했다.