C++ Type Casting – 3ª e ultima parte

Novembro 5, 2008

No post anterior vimos como realizar as operações de casting usando os novos operadores do C++, neste post vamos ver como realizar casting com os smart pointers da Boost , estes operadores podem ser usados com o shared_ptr e o intrusive_ptr.

Mas primeiramente, porque existem operadores de cast específicos da Boost? Pelo fato de que os operadores do C++ não estão preparados para lidar com smart pointers e contagem de referências, dessa forma, caso se utilize um operador padrão do C++ a contagem de referência do objeto pode se tornar invalida, resultando em um objeto sendo destruído mais de uma vez. Exemplo:


enum Eventos_e
{
    TIRO,
    ABRIR_PORTA
};

class Objeto
{
    public:
        virtual void Evento(int tipo, void *param) = 0;
        virtual void Atualizar()=0;
};

class Monstro: public Objeto
{
    public:
        virtual void Evento(int tipo, void *param);
        virtual void Atualizar();
       
    private:
        int m_energia;
};

Com base na hierarquia acima, vamos criar alguns objetos e fazer um cast:


int main(int, char **)
{
    using namespace boost;

    shared_ptr<Objeto> obj(new Monstro());
   
    shared_ptr<Monstro> monstro(static_cast<Monstro *>(obj.get()));   
}

Repare que na linha onde é feito o cast é usado o método get do shared_ptr para se obter uma referência ao objeto que obj armazena, depois é feito o cast e o ponteiro resultante é utilizado para inicializar o ponteiro “monstro”, note que monstro foi inicializado com um ponteiro comum, não com outro shared_ptr, ou seja, para o shared_ptr “monstro” ninguém até o momento gerenciava esse ponteiro, então ele vai simplesmente começar uma nova contagem de referências, dessa forma, quando a função terminar de executar, ambos os smart pointers vão destruir o objeto Monstro, resultando em um comportamento indefinido.

Para evitar esses problemas foram criados os casts a seguir:

Cada um dos casts acima deve ser usado nas mesmas situações dos casts do C++, a diferença é que eles devem ser apenas usados quando os objetos envolvidos são gerenciados por smart pointers.

No caso do exemplo anterior, o código correto é listado abaixo:


int main(int, char **)
{
    using namespace boost;

    shared_ptr<Objeto> obj(new Monstro());
   
    shared_ptr<Monstro> monstro(static_pointer_cast<Monstro>(obj)));   
}

Note que as operações de cast da boost são idênticas as do C++, a diferença é o nome do operador usado.

As operações de cast da Boost devem ser sempre usadas quando é necessário fazer casts entre ponteiros gerenciados por smart pointers da mesma, nos outros casos, deve-se utilizar os operadores do C++.


Boost 1.37.0

Novembro 3, 2008

Noticia rápida, foi disponibilizado hoje uma nova versão da Boost, versão 1.37.0, que além de consertar bugs e adicionar algumas funcionalidades as bibliotecas existentes adiciona uma nova chamada Proto, que é um kit de ferramentas para construção de compiladores para linguagens embutidas, detalhe que não precisa nem compilar para usar!