프로그래밍/C/C++

[C++] 스마트포인터 weak_ptr [정보공유의 장]

nanze 2022. 1. 17. 22:34
반응형

C++ 스마트 포인터 weak_ptr 

금일 정리해볼 내용은 스마트 포인터 중 weak_ptr 관련된 내용이다. shared_ptr 은 자신이 참조하고 있는 메모리에 대해 참조 카운터를 증감시킴으로써 객체의 수명을 관리하도록 되어 있었다. 

하지만 weak_ptr 은 shared_ptr 의 참조 카운팅에 포함되지 않는다. shared_ptr 의 소유 포인터를 참조만할 뿐 참조 카운터에는 영향을 주지 않는 것이다. 내부적으로 shared_ptr 을 더 보게 되면 참조 카운터를 관리하는 변수가 두 개로 나뉘어져 있으며 strong reference count 와 weak reference count 이다. shared_ptr 끼리의 참조는 strong reference count 가 증가되며 weak_ptr 에 의한 참조는 weak reference count를 증가시킨다. 하지만 weak refernce count 는 shared_ptr 의 소유 포인터에 대한 메모리 해제에 영향을 주지 않는다. 

 

다음 코드를 확인해보자. 

#include <iostream>
#include <memory>

using namespace std;

int main()
{
    shared_ptr<int> sp1( new int(1));
    
    weak_ptr<int> wp1 = sp1;
    {
        shared_ptr<int> sp2 = wp1.lock();
        if(sp2){
            //do something. 
        }
    }
    sp1.reset();
    
    shared_ptr<int> sp3 = wp1.lock();
    if(sp3){
        //스코프로 진입되지 않는다. 
    }
    
    return 0;
}

위 코드를 보면 알 수 있는 것은 weak_ptr 은 해당 포인터에 접근하기 위해서는 lock() 함수를 사용하여 shared_ptr 로 변환하여 접근하는 방법이 유일하다. 

 

weak_ptr 은 보통 순환 참조 문제를 해결하기 위해서 많이 사용된다. 다음 코드를 보도록 하자. 

#include <iostream>
#include <memory>
#include <vector>

using namespace std;

class Circular;
class Problem
{
public:
    Problem(){}
    ~Problem(){
        m_List.clear();
    }
public:
    void addUnit(const shared_ptr<Circular>& c){
        m_List.push_back(c);
    }
    void DoSomething(){
    }
private:
    vector<shared_ptr<Circular>> m_List;
};

class Circular
{
public:
    void SetProblem(const shared_ptr<Problem>& p){
        m_Problem = p;
    }
    void DoSomething(){
        if(m_Problem.expired() == false){
            shared_ptr<Problem> sp = m_Problem.lock();
            if(sp){
                sp->DoSomething();
            }
        }
    }
    
private:
    weak_ptr<Problem> m_Problem;
    //shared_ptr<Problem> m_Problem;
};

int main()
{
    shared_ptr<Problem> pb(new Problem);
    
    for(int i=0; i<10;i++){
        shared_ptr<Circular> sp(new Circular);
        pb->addUnit(sp);
        sp->SetProblem(pb);
    }
    pb.reset();
    
    return 0;
}

위 코드에서 weak_ptr<Problem> 대신 shared_ptr<Problem> 이 이용된다면 main 함수의 pb.reset() 시 Problem 을 소멸시키고자 하지만 Problem 안에 Circualr 들이 모두 하나씩 가지고 있기 때문에 메모리가 해제되지 않는 문제가 발생한다. 이러한 문제들을 해결하고자 weak_ptr 을 쓰면 좋은 예가 될 수 있다. 

 

이전 포스팅

2022.01.16 - [프로그래밍/C/C++] - [C++] 스마트포인터 unique_ptr [정보공유의 장]

 

[C++] 스마트포인터 unique_ptr [정보공유의 장]

C++ 스마트 포인터(Smart pointer) unique_ptr 이번 포스팅 정리는 스마트 포인터 중 unique_ptr 에 대해서 정리해 보자. unique_ptr 은 소유하는 포인터에 대해 다음과 같은 규칙을 갖는다. 1. 소유 포인터는 한

nanze.tistory.com

 

반응형