방법: weak_ptr 인스턴스 만들기 및 사용

경우에 따라 개체는 참조 수를 증가하지 않고 shared_ptr 기본 개체에 액세스하는 방법을 저장해야 합니다. 일반적으로 이 상황은 인스턴스 간에 shared_ptr 순환 참조가 있는 경우에 발생합니다.

최상의 디자인은 가능하면 언제든지 포인터의 공유 소유권을 방지하는 것입니다. 그러나 인스턴스의 shared_ptr 공유 소유권이 있어야 하는 경우 인스턴스 간에 순환 참조를 사용하지 않습니다. 순환 참조가 불가피하거나 어떤 이유로든 바람직한 경우 weak_ptr 사용하여 하나 이상의 소유자에게 다른 shared_ptr소유자에 대한 약한 참조를 제공합니다. 를 weak_ptr사용하여 기존 관련 인스턴스 집합에 조인하는 조인을 만들 수 있지만 기본 메모리 리소스가 여전히 유효한 경우에만 만들 shared_ptr 수 있습니다. 자체는 weak_ptr 참조 계산에 참여하지 않으므로 참조 수가 0으로 가는 것을 방지할 수 없습니다. 그러나 a를 weak_ptr 사용하여 초기화된 새 복사본을 shared_ptr 가져올 수 있습니다. 메모리가 이미 삭제weak_ptr된 경우 's 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 a vector<shared_ptr<Controller>>로 수정한 다음 출력에서 반환될 때 RunTest 소멸자가 호출되지 않습니다.

참고 항목

스마트 포인터(모던 C++)