Sdílet prostřednictvím


Postupy: Vytváření a používání instancí ukazatelů weak_ptr

Někdy musí objekt uložit cestu pro přístup k objektu shared_ptr, aniž by došlo k navýšení počtu odkazů.Obvykle k této situaci dochází, když máte cyklické odkazy mezi instancemi shared_ptr.

Nejlepší je vyhnout se sdílenému vlastnictví ukazatelů, kdykoli je to možné.Nicméně pokud musíte mít sdílené vlastnictví instancí shared_ptr vyhněte se cyklickým odkazům mezi nimi.Pokud jsou cyklické odkazy nevyhnutelné nebo dokonce výhodnější z nějakého důvodu, použijte weak_ptr k přiřazení slabého odkazu jednomu nebo více vlastníkům na jiný shared_ptr.Pomocí weak_ptr můžete vytvořit shared_ptr, který se připojí k existující sadě souvisejících instancí, ale pouze pokud jsou prostředky základní paměti stále platné.Ukazatel weak_ptr se sám neúčastní počítání odkazů, a proto nemůže počtu odkazů zabránit v dosažení nuly.Lze však použít weak_ptr pro pokus o získání nové kopie shared_ptr, se kterou byla inicializována.Je-li paměť již byla odstraněna, je vyvolána výjimka bad_weak_ptr.Pokud je paměť stále platná, nový sdílený ukazatel zvýší čítač odkazů a zaručuje, že paměť bude platit tak dlouho, dokud proměnná shared_ptr zůstane v oboru.

Příklad

Následující příklad kódu ukazuje případ, kdy se weak_ptr používá k zajištění řádného odstranění objektů, které mají cyklické závislosti.Při prohlížení příkladu předpokládejte, že byl vytvořen pouze poté, co byla zvážena alternativní řešení.Objekty Controller představují některé aspekty procesu počítače a pracují nezávisle.Každý řadič musí být schopen kdykoli zjistit stav ostatních řadičů a každý obsahuje privátní vector<weak_ptr<Controller>> pro tento účel.Každý vektor obsahuje cyklický odkaz a proto jsou použity instance weak_ptr místo 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);
}
  

Jako experiment upravte vektor others na vector<shared_ptr<Controller>> a poté si ve výstupu všimněte, že nejsou vyvolány žádné destruktory při vrácení TestRun.

Viz také

Koncepty

Chytré ukazatele (moderní verze jazyka C++)