본문 바로가기

C++/C, C++, STL

스마트 포인터(Smart pointer)와 종류

이 문서의 내용

    스마트 포인터(Smart pointer)란?

    C++에서 new 키워드를 사용하여 Heap에 동적 할당된 메모리는 반드시 delete 또는 delete[]로 해제해야합니다.

    만약 누락되었을 때는 메모리 누수(Memeory leak)가 발생하는데, 누수 방지를 위한 자동화 기술이 스마트 포인터입니다.

    #include <memory>

    스마트 포인터란 포인터처럼 동작하는 클래스 템플릿의 일종으로 memory 헤더 파일에서 정의합니다.

    더보기

    보통 new 키워드로 기본 포인터(Raw pointer)가 실제 메모리를 가리키도록 초기화합니다.

    그런 다음 기본 포인터를 스마트 포인터에 대입합니다. 이렇게 정의한 스마트 포인터의 수명이 다하면 소멸자는 메모리를 자동으로 해제합니다.

    C++ 11 이전에는 auto_ptr를 사용하였으나, 이후 버전에서는 unique_ptr shared_ptr weak_ptr를 사용합니다.

    스마트 포인터 종류: unique_ptr

    unique_ptr하나의 스마트 포인터만이 특정 객체를 소유하는 개념입니다.

    객체에 대한 소유권을 도입하였으며 해당 객체의 소유권을 지니고 있을 때만 객체를 삭제 할 수 있습니다.

    #include <memory>
    
    unique_ptr<int> ptr0(new int(5));
    unique_ptr<int> ptr1 = move(ptr1);
    ptr1.reset();
    ptr0.reset();

    unique_ptr 인스턴스는 move()를 사용하여 소유권을 이전 할 수 있습니다. 소유권이 이전된 스마트 포인터는 더 이상 해당 객체를 소유하지 않게됩니다.

    더보기

    C++ 인스턴스에 대한 스마트 포인터는 주로 unique_ptr의 사용을 의미합니다.

    C++ 14부터는 make_unique()를 사용해 unique_ptr를 초기화 할 수 있습니다.

    #include<memory>
    
    unique_ptr<int> ptr0 = make_unique<int>(100);
    unique_ptr<int> ptr1 = move(ptr1);
    ptr1.reset();
    ptr0.reset();

    스마트 포인터 종류: shared_ptr

    shared_ptr는 하나의 특정 객체를 참조하는 스마트 포인터가 몇 개인지를 참조하는 스마트 포인터입니다.

    이렇게 참조하고 있는 스마트 포인터의 수를 참조 횟수(Reference count)라고 부릅니다.

    더보기

    참조 횟수는 특정 객체에 새로운 shared_ptr가 추가될 때마다 1씩 증가하며 수명이 다할 때마다 1씩 감소합니다.

    그리고 마지막 shared_ptr의 수명이 다하여 참조 횟수가 0이 되면 delete 키워드를 사용해 메모리를 자동 해제합니다.

    #include<memory>
    
    // count: 1
    shared_ptr<int> ptr0(new int(10));
    std::cout << ptr0.use_count() << std::endl;
    
    // count: 2
    auto ptr1(ptr0);
    std::cout << ptr1.use_count() << std::endl;
    
    // count: 3
    auto ptr2(ptr1);
    std::cout << ptr2.use_count() << std::endl;

    마찬가지로 make_shared()를 사용해 shared_ptr를 초기화 할 수 있습니다.

    #include<memory>
    
    shared_ptr<int> ptr0 = make_shared<int>(100);

    스마트 포인터 종류: weak_ptr

    weak_ptr는 하나 이상의 shared_ptr 인스턴스가 소유하는 객체에 대한 접근을 제공하지만, 참조 횟수에는 카운팅되지 않습니다.

    만약 서로가 상대방을 가리키는 shared_ptr를 가지고 있다면, 참조 횟수는 절대 0이 되지 않으므로 메모리는 영원히 해제되지 않습니다.

    이를 순환 참조(Circular reference)라고 부릅니다.

    weak_ptr는 바로 shared_ptr에서 순환 참조의 오류를 제거하기 위한 목적으로 사용됩니다.

    정리 및 복습

    • 스마트 포인터(Smart pointer)동적 할당된 메모리를 자동으로 해제하는 포인터입니다. 
    • 스마트 포인터를 사용하려면 memory 헤더 파일을 포함시킵니다.
    • C++ 11 이전에는 auto_ptr를 제공합니다.
    • C++ 11 이상에서 사용 가능한 unique_ptr는 하나의 객체에 대한 소유권을 갖습니다. 객체를 다른 unique_ptr에 이전하려면 move()를 사용합니다.
    • C++ 11 이상에서 사용 가능한 shared_ptr는 객체를 참조하는 스마트 포인터의 수를 카운팅합니다. 이를 참조 횟수(Reference count)라고 부릅니다.
    • C++ 11 이상에서 사용 가능한 weak_ptr는 하나 이상의 shared_ptr가 소유하는 객체에 대한 접근을 제공하지만, 참조 횟수에는 카운팅 되지 않습니다.