|
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











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.