mientras miraba un código, me topé con:
throw /*-->*/new std::exception ("//...
y siempre pensé que no necesitas / no deberías usar new
aquí.
¿Cuál es la forma correcta? ¿Ambos están bien? Si es así, ¿hay alguna diferencia?
Por cierto, por lo que puedo ver mientras "grepping" con PowerShell boost libs nunca se usan throw new
.
PD: también encontré un código CLI que usa throw gcnew
. ¿Eso esta bien?
throw gcnew
sería útil, por ejemplo. si desea que el código administrado detecte su excepción. ¿Alguien puede corregirme en eso?System::Exception
es generalmente una referencia a un objeto administrado en el montón recolectado de basura. Siempre he tiradogcnew
y atrapadoSystem::Exception ^
. Por supuesto, también utilizofinally
todo el tiempo en C ++ / CLI, aunque a menudo no se mezclan con excepciones de C ++ en el mismotry
bloque, no estoy seguro de por qué.Respuestas:
La forma convencional de lanzar y capturar excepciones es lanzar un objeto de excepción y capturarlo por referencia (generalmente
const
referencia). El lenguaje C ++ requiere que el compilador genere el código apropiado para construir el objeto de excepción y limpiarlo adecuadamente en el momento apropiado.Lanzar un puntero a un objeto asignado dinámicamente nunca es una buena idea. Se supone que las excepciones le permitirán escribir código más sólido ante condiciones de error. Si lanza un objeto de excepción de la manera convencional, puede estar seguro de que si es capturado por una cláusula catch que nombra el tipo correcto, por a
catch (...)
, ya sea que se vuelva a lanzar o no, se destruirá correctamente en el momento adecuado. (La única excepción es si nunca se detecta, pero esta es una situación no recuperable, se mire como se mire).Si lanza un puntero a un objeto asignado dinámicamente, debe asegurarse de que, sea cual sea el aspecto de la pila de llamadas en el punto en el que desea lanzar su excepción, hay un bloque de captura que nombra el tipo de puntero correcto y tiene la
delete
llamada adecuada . Su excepción nunca debe ser capturada acatch (...)
menos que ese bloque vuelva a lanzar la excepción que luego es capturada por otro bloque de captura que maneja correctamente la excepción.Efectivamente, esto significa que ha tomado la función de manejo de excepciones que debería facilitar la escritura de código robusto y dificulta la escritura de código que sea correcto en todas las situaciones. Esto deja de lado el problema de que será casi imposible actuar como código de biblioteca para el código de cliente que no espera esta característica.
fuente
No es necesario usarlo
new
al lanzar una excepción.Solo escribe:
y capturar como:
Tenga en cuenta que
yourexception
debe derivar de formastd::exception
directa o indirecta.fuente
new
? por qué derivaryourexception
a partirstd::exception
?throw std::exception;
funciona? g ++ no parece compilarlo ...std::exception
es un tipo, y no puedes lanzar un tipo , tienes que lanzar un objeto . Entonces la sintaxis debería ser esta:throw std::exception();
Eso se compilará. Ahora bien, qué tan bueno es eso, es una pregunta completamente diferente.El lanzamiento
new std::exception
es correcto si el sitio de la llamada espera atrapar unstd::exception*
. Pero nadie esperará captar un puntero a una excepción. Incluso si documentas que eso es lo que hace tu función y las personas leen la documentación, es probable que se olviden e intenten captar una referencia a unstd::exception
objeto.fuente
new std::exception
solo es correcto si el sitio de llamada espera capturar un puntero Y espera hacerse cargo de la administración de la excepción de asignación Y nunca habrá casos en los que su función sea llamada por algo que no captura explícitamente el puntero correcto (catch(...)
o ningún manejo) de lo contrario habrá una fuga de objetos. En resumen, esto se puede aproximar como "nunca".Las preguntas frecuentes de C ++ tienen una buena discusión sobre esto:
Básicamente, "a menos que haya una buena razón para no capturar por referencia. Evite capturar por valor, ya que eso hace que se haga una copia y la copia puede tener un comportamiento diferente al que se lanzó. Solo en circunstancias muy especiales debe capturar por puntero". "
fuente
A
es distinto del tipo,A*
así que si lo hagothrow A()
, NO puedocatch(A* e)
entenderlo, ya que es un tipo completamente diferente.El operador nuevo no puede garantizar que nunca generará una excepción. Por esta razón, usarlo para lanzar una excepción "válida" (prevista) produciría un código que no puede garantizarse que no se bloquee. Dado que puede haber solo una excepción a la vez, y su programa intenta lanzar dos antes de que cualquiera de ellas pueda ser detectada, lo mejor que puede hacer una implementación es abortar inmediatamente su programa, por ejemplo, llamando a std :: terminate.
fuente