본문 바로가기

C++

[C++] weak_ptr

 

 

shared_ptr은 위와 같이 서로의 객체를 참조하고 있을 때 문제가 발생한다. 객체가 사라지려면 shared_ptr의 레퍼런스 카운트가 0이 되어야하는데 그러기 위해서는 상대방 객체가 파괴되어야 한다. 하지만 순환 참조를 이루고 있기 때문에 두 shared_ptr들은 해제되지 않는다. 이 문제를 해결하기 위해 weak_ptr을 사용한다.

 

 

 std::string s;
 std::weak_ptr<A> other;

 

weak_ptr을 사용하는 예시로 먼저 weak_ptr을 선언한다.

 

 

 void set_other(std::weak_ptr<A> o) { other = o; }
 std::vector<std::shared_ptr<A>> vec;
  vec.push_back(std::make_shared<A>("자원 1"));
  vec.push_back(std::make_shared<A>("자원 2"));

  vec[0]->set_other(vec[1]);
  vec[1]->set_other(vec[0]);

 

set_other은 weak_ptr을 인수로 받는데, 여기다가 shared_ptr을 집어넣는다. weak_ptr은 생성자로 shared_ptr이나 weak_ptr처럼 이미 제어블록이 만들어진 객체 주소값을 받는다.

 

 

std::shared_ptr<A> o = other.lock();
  if (o) {
    std::cout << "접근 : " << o->name() << std::endl;
  } else {
    std::cout << "이미 소멸됨 ㅠ" << std::endl;
  }

 

weak_ptr 자체로는 원소를 참조할 수 없기 때문에 lock함수로 shared_ptr로 변환한다. lock 함수는 weak_ptr이 가리키는 객체가 아직 메모리에서 살아 있다면 (참조 개수가 0 이 아니라면) 해당 객체를 가리키는 shared_ptr 을 반환하고,  이미 해제가 되었다면 아무것도 가리키지 않는 shared_ptr 을 반환한다. 아무것도 가리키지 않는 shared_ptr은 false로 처리되기 때문에 if문을 통해 확인할 수 있다.

 

참조 개수가 0이되면 shared_ptr이 가리키는 객체는 해제되지만 weak_ptr이 남아있다면 제어 블록은 해제되지 않는다. 제어 블록을 메모리에서 해제하려면 이를 가리키는 weak_ptr도 0개, 즉 weak count 도 0개여야 한다. 그래서 맨 위처럼 순환 참조를 할 때 weak_ptr을 사용하면 reference count가 2로 늘어나지 않고 1로 그대로면서 weak count가 2가 된다.

또 각 포인터를 해제할 수 있게 된다.

 

weak_ptr은 shared_ptr로 다른 shared_ptr을 참조할 때 control block이 두개가 되어버리므로 shared_ptr을 참조할 때 이용하는 것이라고 생각하면 된다. 

 

 

 

'C++' 카테고리의 다른 글

[C++] 음수를 비트로 표현하는 방법(2의 보수), 진법 표현  (0) 2022.06.18
[C++] RAII  (0) 2022.06.17
[C++] override 지정자  (0) 2022.02.22
[C++] shared_ptr  (0) 2022.02.18
[C++] 스마트 포인터, unique_ptr  (0) 2022.02.18