Pergunta

Eu preciso converter um tipo integral que contém um endereço para o tipo de ponteiro real. Eu poderia usar reinterpret_cast da seguinte forma:

MyClass *mc1 = reinterpret_cast<MyClass*>(the_integer);

No entanto, este não executa qualquer verificação em tempo de execução para ver se o endereço em questão realmente detém um objeto MyClass. Quero saber se há algum benefício em primeiro converter para a * void (usando reinterpret_cast) e, em seguida, usando dynamic_cast no resultado. Como esta:

void *p = reinterpret_cast<void*>(the_integer);
MyClass *mc1 = dynamic_cast<MyClass*>(p);
assert(mc1 != NULL);

Há alguma vantagem em usar o segundo método?

Foi útil?

Solução

verificação de tipo em dynamic_cast é implementado de maneiras diferentes por diferentes implementações de C ++; Se você quer uma resposta para sua implementação específica você deve mencionar que a implementação que você está usando. A única forma de responder à questão em geral é a referência à norma ISO C ++.

Por minha leitura da norma, chamando dynamic_cast em um ponteiro nulo é ilegal:

dynamic_cast<T>(v)

"Se T é um tipo de ponteiro, v deve ser um rvalue de um ponteiro para o tipo de classe completa"

(a partir de 5.2.7.2 padrão ISO C ++). void não é um tipo de classe completa, então a expressão é ilegal.

Curiosamente, o tipo de ser fundido para tem permissão para ser um ponteiro nulo, ou seja.

void * foo = dynamic_cast<void *>(some_pointer);

Neste caso, o dynamic_cast sempre tem sucesso, e o valor resultante é um apontador para o objecto de mais derivado apontada por v.

Outras dicas

Não, não há nenhuma vantagem específica em fazê-lo. No momento em que você usa reinterpret_cast, todas as apostas estão fora. É até você para ter certeza que o elenco é válido.

vantagem verdade não sério. Se as void * aponta para algo que não é um ponteiro para um objeto polimórfico você topar com um comportamento indefinido (geralmente uma violação de acesso) imediatamente.

A maneira segura é manter um registro de todos os objetos MyClass ao vivo. É melhor manter este registro em uma std::set<void*>, o que significa que você pode facilmente adicionar, remover e testar elementos.

A razão para armazená-los como void*s é que você não nastyness risco como a criação de ponteiros MyClass* desalinhados de seus números inteiros.

  • Primeiro de tudo int "reinterpretação" para void * é uma má idéia. Se sizeof(int) é 4 e sizeof(void *) é 8 (64x sistema) é mal-formado.

  • Além disso dynamic_cast é válido apenas para o caso das classes polimórficas.

A opção 1 é a sua única (semi) / opção válida portátil.

Opção 2:. Não é C ++ válido como o dynamic_cast (como vazio não é permitido)

A nível implementação requer informações de tipo do tipo de fonte para chegar ao tipo de destino. Não há nenhuma maneira (ou pode haver nenhuma maneira) para obter as informações tipo de fonte de tempo de execução de um * vazio de modo que este não é válido também.

dynamic_cast é usado para cas cima e para baixo a hierarquia de tipo não de tipos desconhecidos.

Como uma nota lateral você provavelmente deve estar usando void * em vez de um inteiro para armazenar um ponteiro sem tipo. Há potencial para um int não ser grande o suficiente para armazenar um ponteiro.

A forma mais segura de ponteiros punho em C ++ é lidar com eles typesafe. Isso significa que:

  • Nunca guarde ponteiros em qualquer outra coisa do que um ponteiro
  • Evite ponteiros void
  • Nunca deixe passar ponteiros para outros processos
  • considerar weak_ptr se você pretende ponteiros uso sobre tópicos

A razão para isto é: o que você está planejando fazer não é seguro e pode ser evitado a menos que você está interagindo com código inseguro (legado?). Neste caso, considere resposta MSalters, mas esteja ciente de que ainda é um aborrecimento.

Se você sabe com certeza que the_integer aponta para uma classe base conhecidos (que tem pelo menos um membro virtual), pode na verdade ser uma vantagem: sabendo que o objeto é de uma classe específica derivada. Mas você teria que reinterpret_cast para sua classe base primeiro e depois fazer o dynamic_cast:

BaseClass* obj = reinterpret_cast<BaseClass*>(the_integer);
MyClass* myObj = dynamic_cast<BaseClass*>(obj);

Usando um void* em dynamic_cast é inútil e simplesmente errado. Você não pode usar dynamic_cast para verificar se há um objeto válido em algum local arbitrário na memória.

Você também deve prestar atenção ao armazenar endereços em variáveis ??do tipo não-ponteiro. Há arquiteturas onde sizeof (void *)! = Sizeof (int), por exemplo LP64.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top