C++ 스마트 포인터 개념 (unique_ptr
, shared_ptr
, weak_ptr
)
1. 개요
1.1 문서 개요
이 문서는 C++ 표준 라이브러리에서 제공하는 스마트 포인터(unique_ptr
, shared_ptr
, weak_ptr
)의 개념, 역할, 사용 방법에 대해 기록하는 문서입니다. 스마트 포인터는 수동적인 메모리 해제 없이 자원의 소유권과 생명주기를 자동으로 관리할 수 있도록 설계된 도구입니다.
2. 내용
2.1 스마트 포인터 개요
스마트 포인터는 std::unique_ptr
, std::shared_ptr
, std::weak_ptr
로 구성되며, 각각의 클래스는 포인터에 대한 소유권 정책과 참조 카운트 관리 방식이 다릅니다.
2.1.1 주요 목적
- 메모리 누수 방지
- 예외 안전성 확보
- 자원 해제를 자동화(RAII)
2.2 unique_ptr
unique_ptr
는 단독 소유권을 가지며, 복사 불가능하고 이동만 가능합니다.
2.2.1 사용 예
#include <memory>
std::unique_ptr<int> uptr = std::make_unique<int>(10);
2.2.2 이동 소유권
std::unique_ptr<int> uptr2 = std::move(uptr); // uptr은 nullptr이 됨
2.2.3 사용자 정의 소멸자
std::unique_ptr<FILE, decltype(&fclose)> fp(fopen("test.txt", "r"), fclose);
2.3 shared_ptr
shared_ptr
는 참조 카운트를 통해 여러 객체가 동일 자원을 공유할 수 있도록 설계된 스마트 포인터입니다.
2.3.1 기본 사용 예
#include <memory>
std::shared_ptr<int> sp1 = std::make_shared<int>(100);
std::shared_ptr<int> sp2 = sp1; // 참조 카운트 증가
2.3.2 참조 카운트 확인
sp1.use_count(); // 현재 공유 중인 객체 수
2.4 weak_ptr
weak_ptr
는 shared_ptr
가 관리하는 자원을 참조만 하며, 소유권을 갖지 않습니다. 순환 참조 방지에 주로 사용됩니다.
2.4.1 사용 예
std::shared_ptr<int> sp = std::make_shared<int>(200);
std::weak_ptr<int> wp = sp;
2.4.2 lock() 함수로 유효성 확인
if (auto tmp = wp.lock()) {
// shared_ptr로 일시 승격
}
2.5 순환 참조와 weak_ptr의 역할
2.5.1 순환 참조 문제 예
struct Node {
std::shared_ptr<Node> next;
};
이 경우 두 객체가 서로를 shared_ptr
로 참조하면 참조 카운트가 0이 되지 않아 메모리 누수가 발생할 수 있습니다.
2.5.2 해결 방법
struct Node {
std::weak_ptr<Node> next;
};
3. 마무리
스마트 포인터는 C++의 메모리 관리에서 수동 해제를 최소화하고 예외 안정성을 높이는 핵심 도구입니다. 각 포인터는 명확한 소유권 정책과 사용 목적을 가지며, 상황에 맞게 적절한 종류를 선택하여 자원의 생명주기를 안전하게 관리할 수 있습니다.