Ponto V!

Home C/C++ Smart Pointers Boost Weak Pointer (weak_ptr)
Bruno Crivelari Sanches
Boost Weak Pointer (weak_ptr)Imprimir
Escrito por Bruno Crivelari Sanches

Para ver o tutorial anterior da série: Boost Shared Pointer

No ultimo tutorial vimos como funciona o shared_ptr da Boost e o problema da referência circular. Pensando em como resolver esse problema foi então criado o weak_ptr (ponteiro fraco), que também é um smart pointer, mas possui algumas restrições de uso:

  • Um weak_ptr só pode ser criado a partir de um shared_pointer
  • O ponteiro armazenado pelo weak_ptr somente pode ser usado após a chamada do método lock.

Voltando ao exemplo anterior, vamos modificar a classe um pouco:

#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <string>

class Person
{
    public:
        typedef boost::shared_ptr<Person> PersonPtr_t;
        typedef boost::weak_ptr<Person> PersonWeakPtr_t;

        inline void SetName(const std::string &name)
        {
            m_Name = name;
        }

        inline void SetFilho(PersonPtr_t ptr)
        {
            m_Filho = ptr;
        }
        
        inline void SetPai(PersonPtr_t ptr)
        {
            m_Pai = ptr;
        }

    private:
        std::string m_Name;

        PersonPtr_t m_Filho;
        PersonWeakPtr_t m_Pai;
};

Agora a classe Person armazena um weak_ptr para o pai ao invés de um shared_ptr. A decisão sobre quem vai ser weak e quem vai ser shared depende do projeto em si. No exemplo acima, tanto faz, escolhi o pai pensando que o certo seria o pai armazenar uma lista de filhos (que não implementei para deixar o exemplo simples) e a estrutura acabaria ficando parecido com uma arvore, e geralmente em arvores o que importa mesmo é a lista de filhos de cada nó, sendo a referencia para o pai apenas uma conveniência.

Mas voltando a weak_ptr, note que o método SetPai recebe como parâmetro um shared_ptr, não um weak_ptr. Implementamos assim pois um weak_ptr deve ser sempre inicializado a partir de um shared_ptr ou um outro weak_ptr. Se for o caso, pode ser adicionado uma sobrecarga com weak_ptr também.

Utilizando a nova classe:

int main(int argc, char **argv)
{
    Person::PersonPtr_t pai(new Person());
    pai->SetName("Pai");

    Person::PersonPtr_t filho(new Person());
    filho->SetName("Filho");
    filho->SetPai(pai);

    pai->SetFilho(filho);

    return 0;
}

Sim! Não mudou nada em relação ao exemplo do tutorial anterior. Para deixar mais interessante, vamos criar um novo método e usá-lo:

#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <string>
#include <iostream>

class Person
{
    public:
        typedef boost::shared_ptr<Person> PersonPtr_t;
        typedef boost::weak_ptr<Person> PersonWeakPtr_t;

        inline void SetName(const std::string &name)
        {
            m_Name = name;
        }

        inline void SetFilho(PersonPtr_t ptr)
        {
            m_Filho = ptr;
        } 

        inline void SetPai(PersonPtr_t ptr)
        {
            m_Pai = ptr;
        }

        inline const std::string &GetName() const
        {
            return(m_Name);
        }

        inline const std::string *GetNomePai()
        {
            PersonPtr_t ptr = m_Pai.lock();
            return(ptr ? &ptr->GetName() : NULL);
        }
    
    private:
        std::string m_Name;

        PersonPtr_t m_Filho;
        PersonWeakPtr_t m_Pai;
};

int main(int argc, char **argv)
{
    using namespace std;

    Person::PersonPtr_t pai(new Person());
    pai->SetName("Pai");

    Person::PersonPtr_t filho(new Person());
    filho->SetName("Filho");
    filho->SetPai(pai);

    pai->SetFilho(filho);

    const std::string *name = filho->GetNomePai();
    cout << "Nome do pai: " << (name ? *name : "sou orfao") << endl;

    return 0;
}

Pronto, agora já sabemos como usar o weak_ptr. Note que no método GetNomePai verificamos se o ponteiro ptr é valido antes de usá-lo. Isto deve ser feito pois um weak_ptr não garante que um objeto vai ser valido, apenas garante que uma referencia é valida ou null.

Isso quer dizer que se fizermos:

int main(int argc, char **argv)
{
    using namespace std;

    Person::PersonPtr_t pai(new Person());
    pai->SetName("Pai");

    Person::PersonPtr_t filho(new Person());
    filho->SetName("Filho");
    filho->SetPai(pai);

    pai->SetFilho(filho);
    pai.reset(); //apagando a referencia

    const std::string *name = filho->GetNomePai();
    cout << "Nome do pai: " << (name ? *name : "sou orfao") << endl;

    return 0;
}

Neste novo exemplo, ao invés do nome do pai, vai ser impresso a mensagem “sou órfão”, porque quando o reset do ponteiro do pai é invocado, o objeto pai é destruído. Nesse caso, o weak_ptr nos retorna null. Se ao invés do weak_ptr estivéssemos usando um ponteiro comum, acessaríamos um ponteiro invalido.

No próximo tutorial, vamos ver como usar smart pointers com vetores (arrays).

Próximo tutorial da série: Boost Scoped Pointer


Comentários (2)
  • Pedro Silva Moreira - PeJuGe  - Muito bom
    avatar

    Realmente muito bom, tenho aproximadamente 1 ano de experiência com C++, agora aprendendo outras linguagens mas sempre me fascino emoção de programar.
    Excelente tutorial, não é muito fácil achar quem poste tutoriais de boost em português.

  • Bruno Crivelari Sanches
    avatar

    Valeu Pedro!

Escrever um comentário
Your Contact Details:
Gravatar enabled
Comentário:
[b] [i] [u] [url] [quote] [code] [img]   
:angry::0:confused::cheer:B):evil::silly::dry::lol::kiss::D:pinch::(:shock:
:X:side::):P:unsure::woohoo::huh::whistle:;):S:!::?::idea::arrow:
Security
Por favor coloque o código anti-spam que você lê na imagem.
LAST_UPDATED2  

Busca

Linguagens

Twitter