usar try que programacion por excepciones excepcion ejemplos como cero catch c++ exception

c++ - try - ¿Capturar una excepción por referencia es peligroso?



try catch en c (4)

De except.throw :

Lanzar una excepción copy-initializes (8.5, 12.8) un objeto temporal, llamado objeto de excepción. El temporal es un valor l y se usa para inicializar la variable declarada en el controlador correspondiente (15.3). Si el tipo del objeto de excepción sería un tipo incompleto o un puntero a un tipo incompleto que no sea (posiblemente calificado por cv), el programa está mal formado.

Es el acto de lanzar la excepción lo que copia el objeto de excepción en el área de excepciones, fuera de cualquier pila. Por lo tanto, es perfectamente legítimo y aconsejable capturar excepciones por referencia, ya que la vida útil del objeto de excepción se extenderá hasta el último catch() posible.

Eche un vistazo a la siguiente excepción lanzando y atrapando:

void some_function() { throw std::exception("some error message"); } int main(int argc, char **argv) { try { some_function(); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; exit(1); } return 0; }

¿Es seguro atrapar la excepción lanzada por referencia?

Mi preocupación es porque la excepción e se coloca en la pila de some_function() . Pero some_function() acaba de regresar, causando que e se destruya. Entonces, en realidad, ahora e apunta a un objeto destruido.

¿Es correcta mi preocupación?

¿Cuál es la forma correcta de pasar la excepción sin copiarla por valor? ¿Debo lanzar new std::exception() para que se coloque en la memoria dinámica?


Debe tomar por referencia, de lo contrario no podría obtener el tipo dinámico correcto del objeto. En cuanto a su vida útil, las garantías estándar, en [except.throw] ,

El objeto de excepción se destruye después de que el último manejador activo restante para la excepción salga por cualquier otro medio que no sea volver a arrojar, o el último objeto de tipo std :: exception_ptr (18.8.5) que se refiere al objeto de excepción se destruye, lo que ocurra más tarde


La captura por referencia constante es exactamente cómo se deben capturar las excepciones. El objeto de excepción no necesariamente vive ''en la pila''. El compilador es responsable de la magia apropiada para que esto funcione.

Por otro lado, su ejemplo no puede compilarse, ya que std::exception solo puede construirse por defecto o copiarse. En este caso, el método what() devolvería un puntero a una cadena vacía (estilo c), lo que no es particularmente útil.

Le sugerimos que arroje un std::runtime_error o std::logic_error según corresponda, o una clase derivada del mismo:

  • logic_error cuando la persona que llama ha solicitado algo fuera de los parámetros de diseño de su servicio.
  • runtime_error cuando la persona que llama ha solicitado algo razonable pero hay factores externos que le impiden cumplir con la solicitud.

http://en.cppreference.com/w/cpp/error/exception


De hecho, es seguro, y recomendado, atrapar por referencia const .

" e se coloca realmente en la pila de some_function() "

No, no lo es ... el objeto realmente lanzado se crea en un área de memoria no especificada reservada para su uso por el mecanismo de manejo de excepciones:

[except.throw] 15.1 / 4: la memoria para el objeto de excepción se asigna de forma no especificada, excepto como se indica en 3.7.4.1. El objeto de excepción se destruye después de que el último manejador activo restante para la excepción salga por cualquier otro medio que no sea volver a arrojar, o el último objeto de tipo std :: exception_ptr (18.8.5) que se refiere al objeto de excepción se destruye, lo que ocurra más tarde .

Si se especifica una variable local para throw , se copia allí si es necesario (el optimizador puede crearla directamente en esta otra memoria). Es por eso...

15.1 / 5 Cuando el objeto lanzado es un objeto de clase, el constructor seleccionado para la inicialización de la copia y el destructor serán accesibles, incluso si la operación de copiar / mover se elude (12.8).

Si no se hace clic en él, podría ayudar imaginar una implementación vagamente así:

// implementation support variable... thread__local alignas(alignof(std::max_align_t)) char __exception_object[EXCEPTION_OBJECT_BUFFER_SIZE]; void some_function() { // throw std::exception("some error message"); // IMPLEMENTATION PSEUDO-CODE: auto&& thrown = std::exception("some error message"); // copy-initialise __exception_object... new (&__exception_object) decltype(thrown){ thrown }; throw __type_of(thrown); // as stack unwinds, _type_of value in register or another // thread_local var... } int main(int argc, char **argv) { try { some_function(); } // IMPLEMENTATION: // if thrown __type_of for std::exception or derived... catch (const std::exception& e) { // IMPLEMENTATION: // e references *(std::exception*)(&__exception_object[0]); ... } }