본문 바로가기

C

c++ weak pointer 정리

weak pointer의 사용 례를 코드로 정리해본다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <memory>
/// <summary>
/// weak pointer는 cyclic dependency between shared_ptr
/// 을 다루는 데 좋다.
/// 
/// </summary>
/// <returns></returns>
int main()
{
    auto sharedPtr = std::make_shared<int>(100);
    std::weak_ptr<int> weakPtr(sharedPtr);
 
    std::cout << "weakPtr.use count(): " << weakPtr.use_count() << std::endl;
    std::cout << "sharedPtr.use count(): " << sharedPtr.use_count() << std::endl;
    std::cout << "weakPtr.expired(): " << weakPtr.expired() << std::endl;
 
    if (std::shared_ptr<int> sharedPtr1 = weakPtr.lock()) {
        std::cout << "sharedPtr: " << *sharedPtr << std::endl;
        std::cout << "sharedPtr1.use_count(): " << sharedPtr1.use_count() << std::endl;
         
    }
    else
    {
        std::cout << "Don't get the resource!" << std::endl;
    }
    
    //std::cout << "sharedPtr1.use_count(): " << sharedPtr1.use_count() << std::endl;
    // shared.use_count 1->2(if)->1
    std::cout << "sharedPtr.use_count() : " << sharedPtr.use_count() << std::endl;
 
    weakPtr.reset();
    if (std::shared_ptr<int> sharedPtr1 = weakPtr.lock())
    {
        std::cout << "*sharedPtr: " << *sharedPtr << std::endl;
        std::cout << "sharedPtr1.use_count(): " << sharedPtr1.use_count() << std::endl;
    }
    else
    {
        std::cout << "Don't get the resource! " << std::endl;
    }
}

 

 

weak_ptr을 쓰는 이유는 object간 cyclic dependency를 없애는 목적도 있다.

mother struct에서 보면

son과 daughter를 setting 할 때 weak_ptr을 사용했다.

그러면 son과 daughter의 reference count가 최초 생성했던 1에서 늘어나지 않는다.

따라서 stack에서 주소와 heap에서 son과 daughter object가 사라지고, 소멸자가 실행된다.

그러면 mother을 reference 하던 son, dauther가 사라졌으므로, mother 또한 stack mother pointer와 heap에서 object가 소멸된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>
#include <memory>
 
struct Son;
struct Daughter;
 
struct Mother {
    ~Mother() {
        std::cout << "Mother gone" << std::endl;
    }
    void setSon(const std::shared_ptr<Son> s) {
        mySon = s;
    }
    void setDaughter(const std::shared_ptr<Daughter> d) {
        myDaughter = d;
    }
    //std::shared_ptr<Son> mySon;
        //std::shared_ptr<const Mother> myMother;
    //
    // Weak pointer로 변경해본다
    std::weak_ptr<Son> mySon;
    std::weak_ptr<Daughter> myDaughter;
};
 
struct Son {
    Son(std::shared_ptr<Mother> m) : myMother{ m } {};
    ~Son() {
        std::cout << "Son gone" << std::endl;
    }
 
    std::shared_ptr<const Mother> myMother;
 
};
 
struct Daughter {
    Daughter(std::shared_ptr<Mother> m) : myMother{ m } {};
    ~Daughter() {
        std::cout << "Son gone" << std::endl;
    }
    std::shared_ptr<const Mother> myMother;
};
 
int main()
{
    std::cout << std::endl;
    {
        // Destructed 되지 않는다.
        // It will not break cyclic dependency...
        std::shared_ptr<Mother> mother = std::make_shared<Mother>();
        std::shared_ptr<Son> son = std::make_shared<Son>(mother);
        std::shared_ptr<Daughter> daughter = std::make_shared<Daughter>(mother);
        mother->setSon(son); // 이 과정에서 son의 reference가 2가 됨. 
                             // stack에서 벗어나면 reference가 1이 되므로 (0이 아니므로)
                             // shared_ptr만으로는 메모리 leak 발생
                             // mother 내부에 weak_ptr을 쓰면 reference가 0이 되므로
                             // memory에서 해제 됨
        mother->setDaughter(daughter);
        std::cout << "mother.use_count(): " << mother.use_count() << std::endl;
        std::cout << "son.use_count(): " << son.use_count() << std::endl;
        std::cout << "dauther.use_count(): " << daughter.use_count() << std::endl;
    }
 
    std::cout << std::endl;
}