스마트 포인터(std::unique_ptr / std::shared_ptr / std::weak_ptr)

왜 쓰나?

스마트 포인터는 new/delete를 직접 관리하는 대신, 수명(lifetime)을 자동으로 관리해서 메모리 누수와 해제 실수를 줄입니다.

std::unique_ptr (단독 소유)

소유권이 하나의 포인터에만 존재합니다. 복사는 불가하고 이동(move) 만 가능합니다.

#include <memory>

int main() {
  auto p = std::make_unique<int>(10); // p가 유일하게 소유
  auto q = std::move(p);              // 소유권 이동 (p는 null처럼 비어 있음)
}

std::shared_ptr (공유 소유)

여러 곳에서 같은 객체를 참조하며, 참조 카운트가 0이 되면 자동 해제됩니다.

#include <iostream>
#include <memory>

int main() {
  auto a = std::make_shared<int>(5);
  auto b = a; // 참조 카운트 증가

  std::cout << *a << ", " << *b << "\n";
}

std::weak_ptr (약한 참조, 순환 참조 방지)

shared_ptr와 함께 쓰이며, 참조 카운트를 늘리지 않습니다. 그래서 서로가 서로를 들고 있는 **순환 참조(cycle)**를 막을 때 유용합니다.

#include <iostream>
#include <memory>

struct Node {
  std::weak_ptr<Node> parent;   // weak: 참조 카운트 증가 안 함
  std::shared_ptr<Node> child;  // shared: 소유
};

int main() {
  auto root = std::make_shared<Node>();
  auto leaf = std::make_shared<Node>();

  root->child = leaf;
  leaf->parent = root;

  // scope 벗어나면 shared는 해제되고, weak은 검사(lock으로 접근)
  if (auto locked = leaf->parent.lock()) {
    std::cout << "parent exists\n";
  }
}

한 줄 요약

  • unique_ptr: 단독 소유
  • shared_ptr: 공유 소유
  • weak_ptr: 공유 소유를 “안전하게 바라보기”(순환 방지)