-
[C++] 스마트 포인터 활용하기C++/C++ 실습 2025. 6. 1. 11:22
스마트 포인터란?
C++에서 스마트 포인터 (Smart Pointer)는 동적 메모리 관리를 자동화해주는 클래스를 의미한다. 기존 new, delete를 통해 동적 메모리 할당을 하던 방식에서 발전된 형태라고 볼 수 있다. 가장 큰 장점으로는 메모리 해제 (delete)를 하지 않더라도 자동적으로 메모리를 해제한다는 점이다.
스마트 포인터 종류
스마트 포인터 설명 std::unique_ptr<T> 단독 소유 포인터이며, 다른 포인터로 복사가 불가능하다. 이동은 가능하다.
std::make_uniqure<T> 함수를 통해 생성할 수 있다. (C++ 14이상부터 가능하며, C++ 11에서는 직접 new 함수를 써야된다.)std::shared_ptr<T> 여러 포인터가 같은 자원을 공유한다. 마지막 포인터가 삭제될 때 자원이 해제된다.
std::make_shared<T> 함수를 통해 생성할 수 있다.std::weak_ptr<T> std::shared_ptr과 함께 사용한다. 참조는 하지만 소유하지 않는다. 순환 참조 방지를 위해 사용된다. std::unique_ptr 예시
#include <iostream> #include <memory> class Dog { public: Dog() { std::cout << "Dog created\n"; } ~Dog() { std::cout << "Dog destroyed\n"; } void bark() { std::cout << "Woof!\n"; } }; int main() { std::unique_ptr<Dog> dog = std::make_unique<Dog>(); // C++14 이상 dog->bark(); // std::unique_ptr<Dog> dog2 = dog; //복사 불가 std::unique_ptr<Dog> dog2 = std::move(dog); //이동 가능 if (!dog) std::cout << "dog is nullptr\n"; }스마트 포인터는 변수형 뿐만 아니라, 클래스에서도 사용 가능하다. std::uniqure_ptr를 통해 Class Dog를 생성하고, 이를 다시 std::move를 써서 dog2로 이전했다. std::move를 통해 복사가 아닌 이동을 했기 때문에, dog에는 더 이상 리소스가 남지 않게 된다.

std::uniqure_ptr 예제 std::shared_ptr 예시
#include <iostream> #include <memory> class Cat { public: Cat() { std::cout << "Cat created\n"; } ~Cat() { std::cout << "Cat destroyed\n"; } void meow() { std::cout << "Meow!\n"; } }; int main() { std::shared_ptr<Cat> cat1 = std::make_shared<Cat>(); std::shared_ptr<Cat> cat2 = cat1; // 공유 소유 std::cout << "Use count: " << cat1.use_count() << "\n"; // 2 cat1->meow(); cat1.reset(); // cat1이 소유권 포기, cat2만 소유 std::cout << "Use count after reset: " << cat2.use_count() << "\n"; // 1 }std::shared_ptr은 공동 소유가 가능하다.
std::shared_ptr<Cat> cat2 = cat1 : 해당 구문을 통해 cat1, cat2는 동일 리소스를 참조할 수 있게 되었다.
use_count() : 해당 shared_ptr의 리소스가 몇 군데에서 공유중인지 확인 가능하다.
reset() : std::shared_ptr의 소유권을 포기하게 된다.

std::shared_ptr 예제 결과 std::weak_ptr 예시
#include <iostream> #include <memory> class B; // 전방 선언 class A { public: std::shared_ptr<B> b_ptr; ~A() { std::cout << "A destroyed\n"; } }; class B { public: std::weak_ptr<A> a_ptr; // 순환 참조 방지 위해 weak_ptr 사용 ~B() { std::cout << "B destroyed\n"; } }; int main() { std::shared_ptr<A> a = std::make_shared<A>(); std::shared_ptr<B> b = std::make_shared<B>(); a->b_ptr = b; b->a_ptr = a; // weak_ptr 사용으로 A, B 모두 정상적으로 파괴됨 }std::weak_ptr은 std::shared_ptr과 달리, 소유하지 않고 참조만 한다. 만약 둘다 std::shared_ptr를 쓸 경우, a는 b를 소유하고, b는 a를 소유하게 되면서, 순환 참조 및 메모리 누수가 발생하게 된다. 이를 해결하기 위해, 둘 중에 한 개만 weak_ptr를 적용하게 된다면, 순환 참조 및 메모리 누수를 막을 수 있다.

weak_ptr 예시 a가 소멸되면서, 자동적으로 b도 소멸된다. 따라서, 이후 b는 추가적으로 소멸되지 않는다. 만약 B에 weak_ptr 대신 shared_ptr를 쓰게된다면, a, b 모두 소멸되지 않는 현상이 발생한다.
개념 참조 소유 의미 객체를 가리키기만 함 객체의 생명주기를 책임짐 책임 객체가 죽으면 따라감 객체가 살아있게 만드는 역할 생명 주기 다른 소유자에게 의존 내가 삭제되면, 같이 삭제됨 스마트 포인터 weak_ptr shared_ptr, unique_ptr 'C++ > C++ 실습' 카테고리의 다른 글
[C++] 람다 함수 활용 방법 (Lambda Expression) (0) 2025.05.18 [C++] ADL (Argument Dependent Lookup) 이해하기 (0) 2024.11.10