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:
- static_pointer_cast: equivalente ao static_cast
- const_pointer_cast: equivalente ao const_cast
- dynamic_pointer_cast: equivalente ao dynamic_cast
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++.
novembro 6, 2008 às 10:56 |
O mesmo ocorre quando se usa mem_fun da std com shared_ptrs, em alguns compiladores mais modernos é possivel usar o mem_fun, mais em alguns é nescessario usar o mem_fn da boost
Otimo Artigo!
novembro 6, 2008 às 12:50 |
É verdade, bom que ja fica anotado para os leitores!
Obrigado skhaz!
novembro 17, 2008 às 12:45 |
Cara, li alguns posts seus e estão muito legais!
Parabéns ae!
Abraço.
novembro 18, 2008 às 11:02 |
Obrigado Murilo!
maio 8, 2009 às 7:51 |
[...] Os diversos tipos de casting [...]