C++ 스마트 포인터

mingu Lee·2025년 11월 30일

CS

목록 보기
8/21

C++의 스마트 포인터는 일반적인 Raw Pointer의 단점인 메모리 누수(memory leak)잘못된 메모리 접근(dangling pointer) 문제를 해결하기 위해 도입된 객체 wrapper이다.

스마트 포인터는 일반적인 포인터처럼 동작하지만, 객체를 소유하고 해당 객체가 더 이상 필요하지 않을 때 자동으로 메모리를 해제하는 기능을 제공한다.

이는 C++의 RAII (Resource Acquisition Is Initialization) 원칙을 활용하여 리소스 관리를 객체의 수명 주기에 묶어 처리함으로써 프로그래머가 수동으로 delete를 호출할 필요를 없애준다.

스마트 포인터의 종류


1. std::unique_ptr


std::unique_ptr은 배타적 소유권을 관리한다.

즉, 하나의 std::unique_ptr 인스턴스만이 특정 동적 할당 메모리 블록을 소유할 수 있다.

  • 특징:
    • 복사 불가능: 복사 생성자나 복사 대입 연산자가 정의되어 있지 않기에 오직 이동(move)만 가능
    • 저비용: 소유권 관리에 오버헤드가 거의 없어 세 가지 스마트 포인터 중 가장 효율적
    • 자동 해제: std::unique_ptr가 해당 스코프를 벗어나거나 소멸될 때, 소유하고 있던 메모리를 자동 해제
  • 예시:
{
  // 1. 생성 (가장 권장되는 방식: std::make_unique)
  std::unique_ptr<int> ptr1 = std::make_unique<int>(100);

  // 2. 소유권 이전 (move)
  std::unique_ptr<int> ptr2 = std::move(ptr1); // ptr1은 nullptr이 되고, ptr2가 소유권을 갖는다.

  // 3. Raw Pointer 접근
  int value = *ptr2;
}
// 4. 범위를 벗어나면 ptr2가 소유한 메모리 자동 해제

2. std::shared_ptr


std::shared_ptr은 공동 소유권을 관리한다.

여러 shared_ptr 인스턴스가 동일한 동적 할당 메모리를 공유하고 소유한다.

  • 특징:
    • 참조 카운팅: 소유권을 공유하는 인스턴스의 수를 추적하는 Control Block을 유지
    • 자동 해제: 참조 카운트가 0이 될 때 메모리를 해제
    • 복사 가능: 복사할 때마다 참조 카운트가 증가
  • 예제:
// 1. 생성 (가장 권장되는 방식: std::make_shared)
std::shared_ptr<int> s_ptr1 = std::make_shared<int>(200);

// 2. 복사 (공동 소유, 참조 카운트 증가)
std::shared_ptr<int> s_ptr2 = s_ptr1; // s_ptr1과 s_ptr2 모두 소유하며, 카운트는 2.

// 3. 참조 카운트 확인
// int count = s_ptr1.use_count(); // count == 2

3. std::weak_ptr


std::weak_ptr은 순환 참조 문제를 해결하기 위해 사용된다.

소유권 없이 shared_ptr 객체를 관찰한다.

  • 특징:
    • 비소유: weak_ptr는 shared_ptr의 참조 카운트에 영향을 주지 않음
    • 순환 참조 방지: 두 객체가 서로 참조할 때 발생하는 메모리 누수를 방지
    • 유효성 검사:
      • 메모리에 접근하려면 반드시 lock() 메서드를 통해 shared_ptr로 승격해야 함
      • 만약 원본 객체가 이미 해제되었다면, lock()nullptr을 반환
  • 예시:
std::shared_ptr<int> shared_data = std::make_shared<int>(300);

// 1. weak_ptr 생성 (공유 소유권 객체를 참조)
std::weak_ptr<int> weak_ref = shared_data;

// shared_data = nullptr; // 원본 shared_ptr이 소멸되면 메모리 해제됨

// 2. 메모리 접근을 위한 lock() 및 유효성 검사
if (std::shared_ptr<int> safe_access = weak_ref.lock()) {
    // lock()에 성공했으므로 메모리가 유효함
    // int value = *safe_access; 
} else {
    // 원본 shared_ptr이 이미 소멸되어 메모리가 해제되었음
}
profile
Github: https://github.com/dlalsrn

0개의 댓글