Bagikan melalui


Cara: Membuat dan menggunakan instans weak_ptr

Terkadang objek harus menyimpan cara untuk mengakses objek yang mendasar dari shared_ptr tanpa menyebabkan jumlah referensi bertambah. Biasanya, situasi ini terjadi ketika Anda memiliki referensi siklik antar shared_ptr instans.

Desain terbaik adalah menghindari kepemilikan pointer bersama kapan pun Anda bisa. Namun, jika Anda harus memiliki kepemilikan shared_ptr instans bersama, hindari referensi siklik di antaranya. Ketika referensi siklik tidak dapat ditolak, atau bahkan lebih disukai karena alasan tertentu, gunakan weak_ptr untuk memberi satu atau beberapa pemilik referensi lemah ke yang lain shared_ptr. Dengan menggunakan weak_ptr, Anda dapat membuat shared_ptr yang bergabung ke sekumpulan instans terkait yang ada, tetapi hanya jika sumber daya memori yang mendasar masih valid. Itu weak_ptr sendiri tidak berpartisipasi dalam penghitungan referensi, dan oleh karena itu, itu tidak dapat mencegah jumlah referensi masuk ke nol. Namun, Anda dapat menggunakan weak_ptr untuk mencoba mendapatkan salinan shared_ptr baru yang diinisialisasi. Jika memori telah dihapus, weak_ptroperator bool akan mengembalikan false. Jika memori masih valid, penunjuk bersama baru menaikkan jumlah referensi dan menjamin bahwa memori akan valid selama shared_ptr variabel tetap berada dalam cakupan.

Contoh

Contoh kode berikut menunjukkan kasus di mana weak_ptr digunakan untuk memastikan penghapusan objek yang tepat yang memiliki dependensi melingkar. Saat Anda memeriksa contoh, asumsikan bahwa itu dibuat hanya setelah solusi alternatif dipertimbangkan. Objek Controller mewakili beberapa aspek proses mesin, dan mereka beroperasi secara independen. Setiap pengontrol harus dapat mengkueri status pengontrol lain kapan saja, dan masing-masing berisi privat vector<weak_ptr<Controller>> untuk tujuan ini. Setiap vektor berisi referensi melingkar, dan oleh karena itu, weak_ptr instans digunakan alih-alih 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

Sebagai eksperimen, ubah vektor others menjadi vector<shared_ptr<Controller>>, dan kemudian dalam output, perhatikan bahwa tidak ada destruktor yang dipanggil saat RunTest kembali.

Baca juga

Penunjuk Cerdas (Modern C++)