weak_ptr


weak_ptr 用來搭配 shared_ptr,當 shared_ptr 實例用來建構 weak_ptr 實例或指定給 weak_ptr 時,動態配置資源的參考計數並不會增加。例如:

#include <iostream>
#include <memory>
using namespace std;

template<typename T>
struct Node {
    Node(T v) : v(v) {}
    ~Node() {
        cout << v << " deleted" << endl;
    }

    T v;
    weak_ptr<Node<T>> pre;
    weak_ptr<Node<T>> nxt;
};

weak_ptr<Node<int>> foo() {
    auto sp = make_shared<Node<int>>(10);
    weak_ptr<Node<int>> wp = sp;    

    cout << wp.expired() << endl;          // 0
    shared_ptr<Node<int>> sp2 = wp.lock();

    cout << sp2->v << endl;                // 10

    return wp;
}

int main() {
    weak_ptr<Node<int>> wp = foo();
    cout << wp.expired() << endl;          // 1

    return 0;
}

在這個範例中,sp 動態配置的資源要不要刪除,與 wp 沒有關係,weak_ptr 指向的資源還有沒有效(是否被刪除),可以透過 expired 來得知,若要取得資源,可以透過 lock 方法,如果資源仍有效,就會傳回 shared_ptr 實例,否則傳回 nullptr

weak_ptr 用來搭配 shared_ptr,應用場合之一是解決 shared_ptr 形成環狀的問題,例如底下的範例會因為 shared_ptr 形成環狀,使得最後各自的資源並沒有被刪除:

#include <iostream>
#include <memory>
using namespace std;

template<typename T>
struct Node {
    Node(T v) : v(v) {}
    ~Node() {
        cout << v << " deleted" << endl;
    }

    T v;
    shared_ptr<Node<T>> pre;
    shared_ptr<Node<T>> nxt;
};

int main() {
    auto node1 = make_shared<Node<int>>(10);
    auto node2 = make_shared<Node<int>>(20);

    cout << node1.use_count() << endl   // 1
         << node2.use_count() << endl;  // 1

    node1->nxt = node2;
    node2->pre = node1;

    cout << node1.use_count() << endl   // 2
         << node2.use_count() << endl;  // 2   

    return 0;
}

可以看到,shared_ptr 被指定給 shared_ptr,會令參考計數增加,兩個 shared_ptr 實例各自被回收時,各自的參考計數都會是一而不是零,shared_ptr 各自的資源並不會被刪除,若是底下程式:

#include <iostream>
#include <memory>
using namespace std;

template<typename T>
struct Node {
    Node(T v) : v(v) {}
    ~Node() {
        cout << v << " deleted" << endl;
    }

    T v;
    weak_ptr<Node<T>> pre;
    weak_ptr<Node<T>> nxt;
};

int main() {
    auto node1 = make_shared<Node<int>>(10);
    auto node2 = make_shared<Node<int>>(20);

    cout << node1.use_count() << endl   // 1
         << node2.use_count() << endl;  // 1

    node1->nxt = node2;
    node2->pre = node1;

    cout << node1.use_count() << endl   // 1
         << node2.use_count() << endl;  // 1   

    return 0;
}

shared_ptr 被指定給 weak_ptr,不會令參考計數增加,兩個 shared_ptr 實例各自被回收時,各自的參考計數都會是零,shared_ptr 各自的資源可以被刪除。