C++ smart pointer

yun·2023년 11월 12일
  • 참고: https://www.tcpschool.com/cpp/cpp_template_smartPointer

  • C++ 11 버전부터 3가지 smart pointer를 지원한다.

  • Java의 Garbage Collector와 비슷한 개념으로, 더 이상 사용되지 않는 객체에 할당된 메모리를 자동으로 해제한다.

  • malloc을 사용하지 말고 smart pointer에게 맡길 것

1. unique_ptr

  1. 하나의 스마트 포인터만이 특정 객체를 소유할 수 있도록, 객체에 소유권 개념을 도입
  2. 해당 객체의 소유권을 가지고 있을 때만, 소멸자가 해당 객체를 삭제할 수 있다.
  3. unique_ptr 인스턴스는 move() 멤버 함수를 통해 소유권을 이전할 수는 있지만, 복사할 수는 없다.
  4. 소유권이 이전되면, 이전 unique_ptr 인스턴스는 더는 해당 객체를 소유하지 않게 재설정
unique_ptr<int> ptr01(new int(5)); // int형 unique_ptr인 ptr01을 선언하고 초기화함.
auto ptr02 = move(ptr01);          // ptr01에서 ptr02로 소유권을 이전함.
// unique_ptr<int> ptr03 = ptr01;  // 대입 연산자를 이용한 복사는 오류를 발생시킴. 
ptr02.reset();                     // ptr02가 가리키고 있는 메모리 영역을 삭제함.
ptr01.reset();                     // ptr01가 가리키고 있는 메모리 영역을 삭제함.
  1. C++14 이후부터 제공되는 make_unique() 함수를 사용하면 unique_ptr 인스턴스를 안전하게 생성할 수 있다.
#include <iostream>
#include <memory>

using namespace std;

class Person
{
private:
    string name_;
    int age_;

public:
    Person(const string& name, int age); // 기초 클래스 생성자의 선언
    ~Person() { cout << "소멸자가 호출되었습니다." << endl; }

    void ShowPersonInfo();
};

int main(void)
{
    unique_ptr<Person> hong = make_unique<Person>("길동", 29);
    hong->ShowPersonInfo();

    return 0;
}

Person::Person(const string& name, int age) // 기초 클래스 생성자의 정의
{
    name_ = name;
    age_ = age;
    cout << "생성자가 호출되었습니다." << endl;
}

void Person::ShowPersonInfo() { cout << name_ << "의 나이는 " << age_ << "살입니다." << endl; }

2. shared_ptr

  1. 하나의 특정 객체를 참조하는 스마트 포인터가 총 몇 개인지를 참조
  2. 참조하고 있는 스마트 포인터의 개수를 참조 횟수(reference count)라고 한다.
  3. shared_ptr의 수명이 다하여, 참조 횟수가 0이 되면 delete 키워드를 사용하여 메모리를 자동으로 해제
shared_ptr<int> ptr01(new int(5)); // int형 shared_ptr인 ptr01을 선언하고 초기화함.
cout << ptr01.use_count() << endl; // 1
auto ptr02(ptr01);                 // 복사 생성자를 이용한 초기화
cout << ptr01.use_count() << endl; // 2
auto ptr03 = ptr01;                // 대입을 통한 초기화
cout << ptr01.use_count() << endl; // 3
  • make_shared() 함수를 사용하면 shared_ptr 인스턴스를 안전하게 생성할 수 있다. → One Heap Allocation

std::make_shared performs a single heap-allocation accounting for the space necessary for both the control block and the data. In the other case, new Obj("foo") invokes a heap-allocation for the managed data and the std::shared_ptr constructor performs another one for the control block. (https://stackoverflow.com/questions/20895648/difference-in-make-shared-and-normal-shared-ptr-in-c)

Since there's only one allocation, the pointee's memory cannot be deallocated until the control block is no longer in use. A weak_ptr can keep the control block alive indefinitely.

3. weak_ptr

  • 하나 이상의 shared_ptr 인스턴스가 소유하는 객체에 대한 접근을 제공하지만, 소유자의 수에는 포함되지 않는 스마트 포인터
  • 서로가 상대방을 가리키는 shared_ptr를 가지고 있다면, 참조 횟수는 절대 0이 되지 않으므로 메모리는 영원히 해제되지 않는다.
    • 이렇게 서로가 상대방을 참조하고 있는 상황을 순환 참조(circular reference)라고 한다.
    • weak_ptr은 shared_ptr 인스턴스 사이의 순환 참조를 제거하기 위해서 사용된다.

0개의 댓글