스마트 포인터(Smart Pointer)란?
스마트 포인터는 C++의 'raw 포인터'(또는 'bare 포인터')를 감싸는 래퍼(wrapper) 클래스입니다. 단순히 메모리 주소만 저장하는 일반 포인터와 달리, 스마트 포인터는 자신이 가리키는 리소스(주로 힙 메모리)의 생명주기를 관리합니다.
예를 들어, 프로그래머가 delete 호출을 잊어버리거나 예외 발생으로 인해 해당 메모리 위치에 대한 참조가 사라지는 상황을 생각해 볼 수 있습니다. 스마트 포인터는 이런 경우에도 자동으로 메모리를 해제해 주기 때문에, 마치 가비지 컬렉터(garbage collector)처럼 동작한다고 볼 수 있습니다.
대표적인 스마트 포인터 종류
C++11부터 표준 라이브러리(<memory>)에서 제공하는 대표적인 스마트 포인터는 다음과 같습니다.
- std::unique_ptr: 단 하나의 소유자만 허용하는 스마트 포인터입니다. 복사할 수 없고 소유권 이동(move)만 가능하며, 오버헤드가 거의 없어 기본 선택지로 권장됩니다.
- std::shared_ptr: 참조 카운팅(reference counting) 방식으로 여러 개체가 하나의 객체를 공유할 수 있습니다. 마지막 소유자가 사라질 때 메모리가 해제됩니다.
- std::weak_ptr:
shared_ptr의 순환 참조(circular reference) 문제를 해결하기 위해 사용되며, 객체의 소유권 없이 참조만 유지합니다.
언제 스마트 포인터를 사용해야 할까?
결론부터 말하면, 거의 항상 스마트 포인터를 사용하는 것이 좋습니다.
포인터 사용의 가장 큰 고통은 바로 수동 메모리 관리와 메모리 누수(memory leak)입니다. 개발자가 직접 new와 delete를 짝지어 호출해야 하며, 실수 한 번이면 누수나 댕글링 포인터(dangling pointer)로 이어질 수 있습니다. 스마트 포인터는 RAII(Resource Acquisition Is Initialization) 원칙에 따라 이 두 가지 문제를 모두 제거합니다.
따라서 특별한 이유(예: 임베디드 환경에서의 세밀한 제어, C API 연동 등)가 없다면, raw 포인터로 동적 메모리를 직접 관리하지 말고 스마트 포인터를 사용하는 것이 안전하고 유지보수하기 쉬운 코드를 작성하는 길입니다. raw 포인터는 소유권이 없는 단순 참조(관찰) 용도로만 사용하는 것이 현대 C++의 권장 스타일입니다.