建議使用 Visual Studio 2017

如何:建立和使用 weak_ptr 執行個體

 

如需 Visual Studio 2017 的最新文件請參閱 Visual Studio 2017 文件

有時候,物件必須以存取 shared_ptr 基礎物件而不造成參考計數遞增的方式來儲存。 當 shared_ptr 執行個體之間有循環參考存在時,通常會發生這種情況。

最好的設計是盡可能避免共用指標擁有權。 不過,如果您必須擁有 shared_ptr 執行個體的共用擁有權,請避免在它們之間產生循環參考。 當循環參考無法避免,或者由於某種原因反而比較好時,請使用 weak_ptr 將另一個 shared_ptr 的參考指定給一個或多個擁有者。 使用 weak_ptr,可建立 shared_ptr 以聯結一組現有的相關執行個體,但是只有在基礎記憶體資源有效的情況下才有可能。 weak_ptr 本身不會參與參考計數,因此,它無法防止參考計數變成零。 不過,您可以使用 weak_ptr,嘗試取得用來初始化之 shared_ptr 的新複本。 如果記憶體已經刪除,會擲回 bad_weak_ptr 例外狀況。 如果記憶體仍然有效,新的共用指標會遞增參考計數,並保證只要 shared_ptr 變數保持在範圍中,記憶體就是有效。

下列程式碼範例示範使用 weak_ptr 確保正確刪除有循環相依性之物件的案例。 當您可以檢查這個範例,假設它是在考慮替代方案之後建立的。 Controller 物件表示電腦處理序的某些方面,這些物件會獨立運作。 每個控制器都必須可以隨時查詢其他控制器的狀態,而且每個控制器都包含此用途的私用 vector<weak_ptr<Controller>>。 每個向量包含循環參考,因此使用 weak_ptr 執行個體而不是 shared_ptr

#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

class Controller 
{
public:
    int Num;
    wstring Status;
    vector<weak_ptr<Controller>> others;
    explicit Controller(int i) : Num(i) , Status(L"On")
    {
        wcout << L"Creating Controller" << Num << endl;
    }

    ~Controller()
    {
        wcout << L"Destroying Controller" << Num << endl;
    }

    // Demonstrates how to test whether the  
    // pointed-to memory still exists or not. 
    void CheckStatuses() const
    {
        for_each(others.begin(), others.end(), [] (weak_ptr<Controller> wp)
        {
            try
            {
                auto p = wp.lock();
                wcout << L"Status of " << p->Num << " = " << p->Status << endl;
            }

            catch (bad_weak_ptr b)
            {
                wcout << L"Null object" << endl;
            }                
        });
    }
};

void RunTest()
{
    vector<shared_ptr<Controller>> v;

    v.push_back(shared_ptr<Controller>(new Controller(0)));
    v.push_back(shared_ptr<Controller>(new Controller(1)));
    v.push_back(shared_ptr<Controller>(new Controller(2)));
    v.push_back(shared_ptr<Controller>(new Controller(3)));
    v.push_back(shared_ptr<Controller>(new Controller(4)));

    // Each controller depends on all others not being deleted. 
    // Give each controller a pointer to all the others. 
    for (int i = 0 ; i < v.size(); ++i)
    {
        for_each(v.begin(), v.end(), [v,i] (shared_ptr<Controller> p)
        {
            if(p->Num != i)
            {
                v[i]->others.push_back(weak_ptr<Controller>(p));
                wcout << L"push_back to v[" << i << "]: " << p->Num << endl;
            }
        });        
    }

    for_each(v.begin(), v.end(), [](shared_ptr<Controller>& p)
    {
        wcout << L"use_count = " << p.use_count() << endl;
        p->CheckStatuses();
    });
}

int main()
{    
    RunTest(); 
    wcout << L"Press any key" << endl;
    char ch;
    cin.getline(&ch, 1);
}

建立 Controller0
建立 Controller1
建立 Controller2
建立 Controller3
建立 Controller4
push_back to v[0]: 1
push_back to v[0]: 2
push_back to v[0]: 3
push_back to v[0]: 4
push_back to v[1]: 0
push_back to v[1]: 2
push_back to v[1]: 3
push_back to v[1]: 4
push_back to v[2]: 0
push_back to v[2]: 1
push_back to v[2]: 3
push_back to v[2]: 4
push_back to v[3]: 0
push_back to v[3]: 1
push_back to v[3]: 2
push_back to v[3]: 4
push_back to v[4]: 0
push_back to v[4]: 1
push_back to v[4]: 2
push_back to v[4]: 3
use_count = 1
狀態 1 = On
Status of 2 = On
Status of 3 = On
Status of 4 = On
use_count = 1
Status of 0 = On
Status of 2 = On
Status of 3 = On
Status of 4 = On
use_count = 1
Status of 0 = On
狀態 1 = On
Status of 3 = On
Status of 4 = On
use_count = 1
Status of 0 = On
狀態 1 = On
Status of 2 = On
Status of 4 = On
use_count = 1
Status of 0 = On
狀態 1 = On
Status of 2 = On
Status of 3 = On
Destroying Controller0
Destroying Controller1
Destroying Controller2
Destroying Controller3
Destroying Controller4
按任意鍵 在此做個實驗,請將向量 others 修改為 vector<shared_ptr<Controller>>,然後在輸出中注意觀察,當 TestRun 傳回時並沒有叫用任何解構函式。

智慧型指標

顯示: