如何:建立和使用weak_ptr實例

有時候物件必須儲存存取shared_ptr 基礎物件 的方法,而不會造成參考計數遞增。 一般而言,當您在實例之間 shared_ptr 有迴圈參考時,就會發生這種情況。

最佳設計是盡可能避免共用指標的擁有權。 不過,如果您必須擁有實例的 shared_ptr 共用擁有權,請避免它們之間的迴圈參考。 當迴圈參考不可避免,或甚至基於某些原因,請使用 weak_ptr 為一或多個擁有者提供另一 shared_ptr 個 的弱式參考。 藉由使用 weak_ptr ,您可以建立 shared_ptr 聯結至現有相關實例集的 ,但前提是基礎記憶體資源仍然有效。 本身 weak_ptr 不會參與參考計數,因此,它無法防止參考計數進入零。 不過,您可以使用 weak_ptr 來嘗試取得其初始化之 的新複本 shared_ptr 。 如果記憶體已經刪除, weak_ptr 則 的 bool 運算子會傳 false 回 。 如果記憶體仍然有效,新的共用指標會遞增參考計數,並保證只要變數留在範圍中,記憶體就會有效 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) {
         auto p = wp.lock();
         if (p)
         {
            wcout << L"Status of " << p->Num << " = " << p->Status << endl;
         }
         else
         {
            wcout << L"Null object" << endl;
         }
      });
   }
};

void RunTest()
{
   vector<shared_ptr<Controller>> v{
       make_shared<Controller>(0),
       make_shared<Controller>(1),
       make_shared<Controller>(2),
       make_shared<Controller>(3),
       make_shared<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);
}
Creating Controller0
Creating Controller1
Creating Controller2
Creating Controller3
Creating 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
Status of 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
Status of 1 = On
Status of 3 = On
Status of 4 = On
use_count = 1
Status of 0 = On
Status of 1 = On
Status of 2 = On
Status of 4 = On
use_count = 1
Status of 0 = On
Status of 1 = On
Status of 2 = On
Status of 3 = On
Destroying Controller0
Destroying Controller1
Destroying Controller2
Destroying Controller3
Destroying Controller4
Press any key

作為實驗,請將向量 others 修改為 vector<shared_ptr<Controller>> ,然後在輸出中,請注意傳回時 RunTest 不會叫用解構函式。

另請參閱

智慧型指標 (現代 C++)