Pergunta

Existe alguma boas práticas relacionadas com o tratamento de erros dynamic_cast (não exceto a usá-lo quando você não tem que)? Eu estou querendo saber como eu deveria ir sobre NULL e bad_cast ele pode lançar. Devo verificar para ambos? E se eu pegar bad_cast ou detectar NULL eu provavelmente não pode recuperar de qualquer maneira ... Por agora, eu estou usando assert para verificar se dynamic_cast não retornou valor NULL. Você aceitaria essa solução em uma revisão de código?

Foi útil?

Solução

Se o dynamic_cast deve ter sucesso, seria uma boa prática para uso boost::polymorphic_downcast vez, que vai um pouco algo como isto:

assert(dynamic_cast<T*>(o) == static_cast<T*>(o));
return static_cast<T*>(o);

Desta forma, você irá detectar erros na compilação de depuração e, ao mesmo tempo que evita a sobrecarga de tempo de execução em uma compilação de lançamento.

Se você suspeitar que o elenco pode falhar e você quiser detectá-lo, use dynamic_cast e elenco para um tipo de referência. Este elenco vai jogar bad_cast em caso de erro, e derrubar seu programa. (Isso é bom se, como você diz, você não está indo para recuperar de qualquer maneira)

T& t = dynamic_cast<T&>(o);
t.func(); //< Use t here, no extra check required

Use dynamic_cast a um tipo de ponteiro apenas se o 0-ponteiro faz sentido no contexto. Você pode querer usá-lo em uma if assim:

if (T* t = dynamic_cast<T*>(o)) {
    t->func(); //< Use t here, it is valid
}
// consider having an else-clause

Com esta última opção que você precisa ter certeza de que o caminho de execução faz sentido se as dynamic_cast retorna 0.

Para responder à sua pergunta diretamente: Eu preferiria uma das duas primeiras alternativas que dei a ter um assert explícita no código:)

Outras dicas

bad_cast só é acionada quando lançando referências

dynamic_cast< Derived & >(baseclass)

NULL é devolvido quando casting ponteiros

dynamic_cast< Derived * >(&baseclass)

Assim, nunca há uma necessidade de verificar ambos.

Assert pode ser aceitável, mas isso depende muito do contexto, então, novamente, isso é verdade para praticamente todos os assert ...

Sim e não.

boost::polymorphic_downcast<> é certamente uma boa opção para lidar com erros de dynamic_cast<> durante a fase de depuração. No entanto vale a pena mencionar que polymorphic_downcast<> deve ser utilizado quando é possível prever o tipo polimórfico passado em tempo de compilação , caso contrário o dynamic_cast<> deve ser usado no lugar do mesmo.

No entanto, uma sequência de:

if (T1* t1 = dynamic_cast<T1*>(o)) 
{ }
if (T2* t2 = dynamic_cast<T2*>(o)) 
{ }
if (T3* t3 = dynamic_cast<T3*>(o)) 
{ }

denota um design muito ruim que deve ser resolver, por polimorfismo e funções virtuais .

Depende ...; -)

Se eu realmente esperava que o dynamic_cast para me dar algo útil, por exemplo, se eu e mais ninguém adicionou um tipo polimórfico a um contêiner de ponteiros para uma classe base, então eu iria com o elenco de referência e deixe a matança std::bad_cast minha aplicação -. não haveria muito o que fazer, realmente

No entanto, se eu estou consultando um tipo polimórfico para alguma capacidade exposta por uma interface que não tem necessariamente de implementar, em seguida, eu iria com o elenco ponteiro e, em seguida, um NULL não seria um erro ( a não ser, é claro, eu esperava a capacidade de realmente estar lá - mas então eu tinha ido para o elenco de referência, em primeiro lugar ...)

Eu concordo com a resposta 'depende', e também adicionar "degradação graciosa": só porque uma conversão falhar em algum lugar não é motivo suficiente para permitir que o aplicativo falhar (e que o usuário perder a sua / o seu trabalho, etc .). Eu recomendo uma combinação de afirma e programação defensiva:

ptr = dynamic_cast<MyClass>(obj);
ASSERT(ptr);
if(ptr)
{
   // do stuff
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top