Static_cast e reinterpret_cast parecem funcionar bem para converter void * para outro tipo de ponteiro. Existe uma boa razão para favorecer um sobre o outro?
Static_cast e reinterpret_cast parecem funcionar bem para converter void * para outro tipo de ponteiro. Existe uma boa razão para favorecer um sobre o outro?
Respostas:
Usostatic_cast
: é o elenco mais restrito que descreve exatamente qual conversão é feita aqui.
Há um equívoco de que o uso reinterpret_cast
seria uma correspondência melhor porque significa "ignorar completamente a segurança de tipo e apenas transmitir de A para B".
No entanto, isso realmente não descreve o efeito de a reinterpret_cast
. Em vez disso, reinterpret_cast
possui vários significados, e todos afirmam que "o mapeamento realizado por reinterpret_cast
é definido pela implementação". [5.2.10.3]
Mas, no caso específico de transmissão de void*
paraT*
o mapeamento, é completamente bem definido pelo padrão; ou seja, atribuir um tipo a um ponteiro sem tipo, sem alterar seu endereço.
Esta é uma razão para preferir static_cast
.
Além disso, e sem dúvida mais importante, é o fato de que todo uso de reinterpret_cast
é absolutamente perigoso, porque converte qualquer coisa para qualquer outra coisa realmente (para ponteiros), enquanto static_cast
é muito mais restritivo, proporcionando um melhor nível de proteção. Isso já me salvou de bugs, onde acidentalmente tentei coagir um tipo de ponteiro para outro.
Esta é uma pergunta difícil. Por um lado, o Konrad faz um excelente argumento sobre a definição de especificação para reinterpret_cast , embora na prática provavelmente faça o mesmo. Por outro lado, se você estiver transmitindo entre tipos de ponteiro (como é bastante comum ao indexar na memória por um caractere *, por exemplo), static_cast gerará um erro do compilador e você será forçado a usar o reinterpret_cast de qualquer maneira.
Na prática, uso reinterpret_cast porque é mais descritivo da intenção da operação de conversão. Você certamente poderia argumentar que um operador diferente designasse apenas reinterpretações de ponteiros (que garantiam o mesmo endereço retornado), mas não há um no padrão.
reinterpret_cast
!
Sugiro usar sempre o elenco mais fraco possível.
reinterpret_cast
pode ser usado para converter um ponteiro em um float
. Quanto mais estrutura o elenco for, mais atenção será necessária.
No caso de char*
, eu usaria elenco de estilo c, até que tenhamos alguns reinterpret_pointer_cast
, porque é mais fraco e nada mais é suficiente.
float f = *reinterpret_cast<const float*>(&p);
float
, o que é falso. Os moldes de expressão void **
para const float *
, em seguida, usa uma operação dereference (que não é um elenco), para converter const float *
a float
.
Minha preferência pessoal é baseada na alfabetização de código como esta:
void* data = something;
MyClass* foo = reinterpret_cast<MyClass*>(data);
foo->bar();
ou
typedef void* hMyClass; //typedef as a handle or reference
hMyClass = something;
const MyClass& foo = static_cast<MyClass&>(*hMyClass);
foo.bar();
Os dois fazem o mesmo no final, mas static_cast parece mais apropriado em um ambiente de aplicativo de middleware, enquanto a reinterpretação do elenco parece mais algo que você veria em uma biblioteca de nível inferior IMHO.