← SEARCHABLE ARCHIVE
C / C++ · 2026-06-23

C++ 기초부터 마스터까지 — 9화

스마트 포인터로 소유권 표현하기

INTERACTIVE READING MODE →

본 블로그 작성 글들은, 강의를 목표로 하고 제작되었습니다. 또한 작성된 글의 정보도 틀렸을 수 있으니, 주의해주세요.

포인터를 사용한다고 해서 문제가 생기는 것은 아니다. 문제는 누가 객체를 파괴해야 하는지 모르는 상태에서 raw pointer를 소유권처럼 사용할 때 생긴다.

스마트 포인터는 소유권을 타입으로 표현한다.

unique_ptr

std::unique_ptr은 단독 소유권을 가진다.

#include <memory>

auto warrior = std::make_unique<Warrior>("Rose");
std::cout << warrior->Attack() << '\n';

직접 new를 호출하지 않고 std::make_unique로 객체를 만든다. unique_ptr이 범위를 벗어나면 소유한 객체도 자동으로 파괴된다.

단독 소유이므로 복사는 할 수 없지만 이동은 가능하다.

std::vector<std::unique_ptr<Character>> party;

auto warrior = std::make_unique<Warrior>("Rose");
party.push_back(std::move(warrior));

std::move 이후 warrior는 비어 있고, 소유권은 vector로 이동한다. std::move 자체가 물건을 옮기는 함수라기보다는 이동할 수 있는 값으로 취급하게 만드는 역할을 한다.

shared_ptr

하나의 몬스터를 활성 목록과 전투 시스템이 함께 소유해야 할 수도 있다. 이때는 std::shared_ptr을 사용할 수 있다.

auto monster = std::make_shared<Monster>(1, "Slime", 30);

std::vector<std::shared_ptr<Monster>> activeMonsters;
std::queue<std::shared_ptr<Monster>> spawnQueue;

spawnQueue.push(monster);
activeMonsters.push_back(monster);

shared_ptr이 복사될 때 객체가 복사되는 것이 아니라 참조 횟수가 증가한다. 마지막 소유자가 사라질 때 실제 객체가 파괴된다.

편하다는 이유로 모든 포인터를 shared_ptr로 만드는 것은 좋지 않다. 누가 주인인지 흐려지고 순환 참조가 생길 수도 있으며 참조 횟수 관리 비용도 있다.

weak_ptr

현재 타깃처럼 객체를 소유하지 않고 관찰만 하고 싶다면 std::weak_ptr을 사용한다.

std::weak_ptr<Monster> currentTarget;

currentTarget = monster;

if (auto target = currentTarget.lock())
{
    std::cout << target->GetHealth() << '\n';
}

weakptr은 객체의 수명을 늘리지 않는다. 대상이 살아 있다면 lock()이 sharedptr을 반환하고, 이미 파괴됐다면 빈 shared_ptr을 반환한다.

정리하면 소유자가 한 명이면 uniqueptr, 여러 시스템이 정말 함께 소유해야 한다면 sharedptr, 소유하지 않고 보기만 한다면 weak_ptr이다.

소유권이 코드에 드러나면 delete를 언제 해야 할지 고민하는 시간도 줄어든다.