ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [c++11] std::weak_ptr의 사용
    프로그래밍/c++ 2015. 7. 23. 12:30
    반응형

    weak_ptr

    약한 포인터(weak pointer)에 관한 설명으로 흔히 사용되는 말은 shared_ptr로 연결된 자료구조의 포인터 참조 고리를 끊기 위해서라는 것이다. 나는 weak_ptr를 다음과 같이 설명하는 편이 더 나을 것이라고 생각한다.

    1. 포인터가 존재할 경우에만 참조해야 하고
    2. (다른 누군가에 의해) 삭제될 수 있으며
    3. 마지막으로 사용된 후에는 소멸자가 호출되어야 하는(그래서 자신이 할당했던 익명 메모리 공간을 제거해야만 하는) 포인터

    고전 게임인 "행성 게임(asteroid game)"을 구현해야 한다고 생각해 보자. 

    모든 행성은 게임에 의해 관리되지만 행성 사이의 충돌을 처리하기 위해서 이웃 행성 정보도 관리해야 한다. 

    행성이 충돌하면 보통 하나 이상의 행성이 소멸된다. 이러한 이웃 행성 목록을 관리할 때는 "살아 있는" 행성만 관리해서는 안 된다(그래서 shared_ptr를 사용할 수는 없음). 

    반면 어떤 행성은 다른 행성이 자신을 가리키고 있을 때에는 소멸되어서는 안 된다(충돌의 결과를 계산하려면 행성이 존재해야 함). 

    마지막으로 한 행성이 소멸될 때에는 자원(그래픽 시스템과의 연결 등을 나타내는 자원)을 반환하기 위해 분명 소멸자가 호출되어야 한다. 우리에게 필요한 것은 아직 살아 있을지도 모르는 행성 목록이며, 따라서 "행성이 존재한다면 그 기간 동안만 가리킬 수 있는" 방법이 필요하다. 

    weak_ptr는 바로 이런 경우에 필요하다.

    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
        void owner()
        {
            // ...
            vector<shared_ptr<Asteroid>> va(100);
            for (int i=0; i<va.size(); ++i) {
                // ... 새로운 행성에 대해 이웃 행성을 계산함 ...
                va[i].reset(new Asteroid(weak_ptr<Asteroid>(va[neighbor]));
                launch(i);
            }
            // ...
        }
    cs

    reset()은 shared_ptr가 새로운 객체를 가리킬 수 있도록 하기 위한 함수다.

    위 "owner" 코드는 너무 간략화된 버전인데, 여기서는 각 새로운 행성(Asteroid)에 대하여 이웃이 하나만 존재한다고 가정하고 있다. 

    위 코드의 핵심은 행성의 이웃을 가리키기 위해 weak_ptr를 사용했다는 점이다. 

    owner는 다른 코드가 참조할 수 있는, 즉 공유되는Asteroid에 대한 소유권을 나타내기 위해 shared_ptr를 사용하였다. 한 행성(Asteroid)에 대한 충돌 계산 코드는 다음과 같은 형태가 될 것이다.

    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
        void collision(weak_ptr<Asteroid> p)
        {
            if (auto q = p.lock()) {    // p.lock은 p가 가리키는 객체에 대한 shared_ptr를 리턴함
                // ... 행성이 아직 존재함: 충돌 계산을 수행함 ...
            }
            else {
                // ... 이런! 가리키던 행성이 이미 소멸되었음: 고려할 필요 없음(이 행성에 대한 weak_ptr을 delete함)
            }
        }
    cs

    행성의 소유주(owner)가 게임을 중지하고 모든 Asteroids를 제거(소유권을 나타내는 여러 shared_ptr를 제거함으로써)하기로 결정했다고 하더라도, 충돌 계산 중인 각 Asteroid은 정상적으로 작업을 마칠수 있다는 사실(p.lock() 호출로 얻은 shared_ptr는 여전히 사용할 수 있으므로 그러함)에 주의하자.

    "평범한" shared_ptr를 사용해야 하는 경우보다 weak_ptr를 사용해야 하는 경우가 드물겠지만, unique_ptr는 더 단순한 소유권을 나타내며(더 효율적이기도 함) 더 이해하기 쉬우므로 shared_ptr 보다 많이 사용되기를 바란다.


    http://pl.pusan.ac.kr/~woogyun/cpp11/C++11FAQ_ko.html#std-weak_ptr

    반응형
Designed by Tistory.