Compartilhar via


Como: criar e usar instâncias weak_ptr

Às vezes, um objeto deve armazenar uma maneira de acessar o objeto subjacente de um shared_ptr sem causar a contagem de referência ser incrementada.Normalmente, esta situação ocorre quando você tem referências cíclicas entre shared_ptr instâncias.

O melhor design é evitar propriedade compartilhada de ponteiros sempre que puder.No entanto, se você deve ter compartilhado apropriar shared_ptr instâncias, evite referências cíclicas entre elas.Quando referências cíclicas são inevitáveis, ou até mesmo preferível por algum motivo, use weak_ptr para dar um ou mais proprietários um fraco referência a outro shared_ptr.Usando um weak_ptr, você pode criar um shared_ptr que associa um conjunto existente de instâncias relacionadas, mas somente se o recurso de memória subjacente ainda é válido.A weak_ptr si não participa de contagem de referência e, portanto, ele não pode impedir a contagem de referência for zero.No entanto, você pode usar um weak_ptr para tentar obter uma nova cópia do shared_ptr com o qual ele foi inicializado.Se a memória já tiver sido excluída, um bad_weak_ptr exceção é lançada.Se a memória ainda é válida, o novo ponteiro compartilhado incrementa a contagem de referência e garante que a memória será válida desde que o shared_ptr variável permanece em escopo.

Exemplo

O exemplo de código a seguir mostra um caso onde weak_ptr é usado para garantir a correta exclusão de objetos que possuem dependências circulares.Como examinar o exemplo, suponha que foi criado depois de soluções alternativas foram consideradas.O Controller objetos representam algum aspecto do processo de máquina e elas operam de forma independente.Cada controlador deve ser capaz de consultar o status dos outros controladores a qualquer momento, e cada um contém um particular vector<weak_ptr<Controller>> para essa finalidade.Cada vetor contém uma referência circular e, portanto, weak_ptr instâncias são usadas em vez de 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);
}

Como exercício, modifique o vetor de others ser um vector<shared_ptr<Controller>>e na saída, observe que nenhuma destrutores são chamados quando TestRun retorna.

Consulte também

Conceitos

Ponteiros inteligentes (guia de programação do C++ moderno)