logo
Contato | Sobre...        
rebarba rebarba

Rodrigo Strauss :: Blog


C++ com sanidade: resolvendo o bug usando Boost

Seguindo a série de possíveis correções para o bug da cópia de um objeto que contém um ponteiro, sugiro agora a correção que eu acho mais fácil e apropriada: usar o shared_ptr do Boost. Essa proposta segue a filosofia C++: fazer tudo com o máximo de simplicidade e reusando as bibliotecas existentes ao máximo.

Para quem não conhece, o Boost é um conjunto de bibliotecas (a maioria de templates) para C++, que é vista pelos usuários como um extensão da biblioteca padrão (namespace std). Essas bibliotecas vão de smart pointers à regular expression, de algoritmos para manipulação de strings à templates metaprogramming. Algumas das bibliotecas do Boost (acho que 10) serão adicionadas ao próximo padrão C++, nomeado provisóriamente como C++0x (0x será o ano de publicação, o último padrão é o C++98).

Como todos já sabem, um trecho de código sempre vale mais do que 100.000.000.000 palavras:

#include <iostream>
#include <boostshared_ptr.hpp>

//
// costumes Win32...
//
#ifndef DWORD
#define DWORD unsigned int
#endif


class CTest1
{
public:
   CTest1() : dwValue(0)
   {}

   ~CTest1()
   {
      // só para termos certeza do que está acontecendo...
      std::cout << "CTest1::~CTest1() | " << (void*)this << std::endl;
   }

   DWORD dwValue;
   std::string strValue;
};



class CTest2
{
private:
   //
   // transformando o ponteiro em um shared_ptr resolve o bug
   //
   boost::shared_ptr<CTest1> m_pTest1;
public:

   CTest2() 
      : m_pTest1(new CTest1)
   {}


   //
   // Não preciso um destrutor para desalocar o ponteiro.
   // E nem precisei usar um linguagem mais limitada ou uma runtime lenta
   //

   CTest2(DWORD dw, const std::string& str)
      : m_pTest1(new CTest1)
   {
      m_pTest1->dwValue = dw;
      m_pTest1->strValue = str;
   }

   ~CTest2()
   {
      std::cout << "CTest2::~CTest2() | " << (void*)this << std::endl;
   }

   //
   // essa versão é a mais recomendada
   //
   const boost::shared_ptr<CTest1>& GetTest1()
   {
      return m_pTest1;
   }

   //
   // vamos renomear. Eu poderia passar o ponteiro diretamente,
   // mas prefiro seguir as regras de ownership do shared_ptr
   // Isso chama-se "safe programming", mais do que possível em C++
   //
   CTest1* GetTest1_old() const
   {
      return m_pTest1.get();
   }

};

int main(int argc, char* argv[])
{
   std::vector<boost::shared_ptr<CTest2> > vecTest2;

   boost::shared_ptr<CTest2> t1(new CTest2), t2(new CTest2(100,"putz grila"));

   //
   // agora nossas variáveis são ponteiros
   //
   t1->GetTest1()->dwValue = 50;
   t1->GetTest1()->strValue = "baba";

   //
   // vamos criar um objeto e fazer uma cópia 
   // do CONTEÚDO de um dos ponteiros
   //
   CTest2 tv3 = *t1;

   //
   // chamando operator=, copiando o valor
   //
   *t2 = tv3;

   //
   // vamos atribuir um ponteiro ao outro.
   // Note que como usamos um shared_ptr, o conteúdo do ponteiro t1 será
   // automaticamente liberado, e não haverá leak
   // "olhe mamãe, sem o garbage collector"
   //
   t1 = t2;
   
   //
   // vamos colocar um t1 no vetor. Isso coloca o ponteiro,
   // e não faz cópia do objeto
   //
   vecTest2.push_back(t1);

   //
   // vamos colocar t2, que é o mesmo ponteiro de t1
   //
   vecTest2.push_back(t2);

   BOOST_ASSERT(t1 == t2);
   BOOST_ASSERT(t1.get() == t2.get());
   BOOST_ASSERT(vecTest2[0] == vecTest2[1]);

   //
   // agora vamos pegá-lo e ver o seu valor
   //
   std::cout << "dwValue = "  << vecTest2[0]->GetTest1()->dwValue  << std::endl;
   std::cout << "strValue = " << vecTest2[0]->GetTest1()->strValue << std::endl;

   return 0;
}

Outros post da série:
Tinha um bug no caminho, no caminho tinha um bug
Por que o bug?
Resolvendo o bug usando um smart pointer feito em casa

Em 06/06/2005 13:11, por Rodrigo Strauss


  
 
 
Comentários
rebarba rebarba
  ::::