Lanzar excepciones con mensaje en C++
- Lanzar excepciones con mensaje usando la excepción estándar de C++ - Argumento no válido
- Lanzar excepciones con mensaje usando la excepción estándar de C++ - Excepción anidada
- Use el error de tiempo de ejecución para lanzar excepciones con el mensaje en C++
- Conclusión
Este artículo explicará cómo lanzar excepciones con un mensaje variable en C++. El lanzamiento de una excepción es el proceso de cambiar el control del programa para evitar bloqueos o desbordamientos.
Se ejecuta colocando un lanzamiento de excepción dentro del programa donde podría ocurrir un problema. Hay varias palabras clave de manejo de excepciones en C++, pero este artículo verá cómo generar excepciones con un mensaje variable.
Lanzar excepciones con mensaje usando la excepción estándar de C++ - Argumento no válido
Este programa utiliza una excepción de argumento no válido
de las excepciones estándar de C++ para lanzar excepciones con un mensaje variable.
Importar paquetes
El programa utiliza dos paquetes de importación, stdexcept
para incluir excepciones estándar de C++ y iostream
para operaciones de entrada y salida.
Método para lanzar una excepción
Este programa definió una función para comparar dos números proporcionados como entrada y arroja un caso de excepción cuando se encuentra una entrada negativa. Aquí se utiliza la excepción estándar std::invalid_argument
.
En este programa se define un método comparar
con dos valores enteros, var_a
y var_b
, como parámetros. Esto usa si
para verificar un número negativo (a, b o ambos) y arroja una excepción si es así.
if (var_a < 0 || var_b < 0) {
throw std::invalid_argument("Negative value encountered");
Método principal
El método main
utiliza las palabras clave de excepción try-catch
para generar excepciones válidas.
El manejo de excepciones se ejecuta llamando al método comparar
dentro de los bloques intentar
. Como las entradas (-1,3)
tienen un número negativo, el bloque try
enviará el argumento al bloque catch
, que lanza excepciones con un mensaje variable e imprime el mensaje.
#include <iostream>
#include <stdexcept>
using namespace std;
int check_neg(int var_a, int var_b) {
if (var_a < 0 || var_b < 0) {
throw std::invalid_argument("Negative value encountered");
}
return 0;
}
int main() {
try {
compare(-1, 3);
} catch (const std::invalid_argument& e) {
std::cout << "booh!";
}
}
Producción :
booh!
--------------------------------
Process exited after 0.006709 seconds with return value 0
Press any key to continue . . .
Lanzar excepciones con mensaje usando la excepción estándar de C++ - Excepción anidada
Las excepciones se pueden anidar entre sí para mostrar varios mensajes de lanzamientos de excepción de forma consecutiva. El programa de esta sección envuelve los mensajes de error en excepciones anidadas, luego lanza excepciones con un mensaje variable en cada ocurrencia y las muestra juntas.
Importar paquetes
Los paquetes de importación utilizados en este programa son:
iostream
stdexcept
exception
string
fstream
Métodos de miembros
El programa tiene tres funciones miembro: print_exception
, open_file
y run
.
Método print_exception
:
Tiene dos parámetros públicos: std::exception& ex
para detectar excepciones std
y una variable entera stage
que se inicializa con el valor cero. Dentro del método, la primera línea std::cerr
se usa para imprimir un mensaje de error que es Excepción encontrada:
, pero se coloca en niveles de anidamiento usando std::string(level,'')
.
El mensaje de error va seguido de ex.what
, donde ex
es un objeto de std::exception
y ex.what
devolverá una cadena explicativa sobre el error que ocurrió.
El bloque try
usa std::rethrow_if_nested(e)
para lanzar una excepción, pero solo en el caso de que el objeto std
ex
se derive de una excepción anidada, lo que ocurre en este programa.
El bloque catch
utiliza un objeto std
nestedException
para volver a llamarse a sí mismo recursivamente mientras aumenta el valor de stage
en 1. El método catch(...)
captura todas las excepciones.
void print_exception(const std::exception& ex, int level = 0) {
std::cerr << std::string(level, ' ') << "Encountered Exception: " << ex.what()
<< '\n';
try {
std::rethrow_if_nested(ex);
} catch (const std::exception& nestedException) {
print_exception(nestedException, stage + 1);
} catch (...) {
}
}
Lo que sucede aquí en el código anterior es que intenta imprimir la cadena explicativa de la excepción. Si la función la encuentra anidada, recurre para imprimir el explicativo de la excepción que contiene.
Método open_archivo
:
La función tiene un único parámetro de cadena std::string& s
, que crea un objeto std::string
y le transfiere un alias s
.
El bloque try-catch
intenta leer un archivo, detecta una excepción cuando el archivo no se puede cargar y lo envuelve en una función anidada.
void open_file(const std::string& s) {
try {
std::ifstream file(s);
file.exceptions(std::ios_base::failbit);
} catch (...) {
std::throw_with_nested(std::runtime_error("Couldn't open " + s));
}
}
Método ejecutar()
:
El método void run()
llama al método open_file
dentro del bloque try
. El bloque catch(...)
atrapa todas las excepciones que surgen a través de std::throw_with_nested
.
Genera una excepción que combina e
con la excepción que se está manejando actualmente.
La excepción que se maneja en ese momento se convierte en la excepción externa y e
se convierte en la excepción anidada. "run() falló"
es el mensaje final impreso.
void run() {
try {
open_file("nonexistent.file");
} catch (...) {
std::throw_with_nested(std::runtime_error("run() failed"));
}
}
Método int main()
:
El método main
llama a la función run()
dentro del bloque try
, mientras que dentro del bloque catch
, el programa llama al método print_exception
mientras pasa e
como parámetro.
Ejecuta las funciones que lanzan excepciones con un mensaje variable, imprime las excepciones capturadas en un formato anidado y muestra un mensaje personalizado con cada lanzamiento de excepción.
int main() {
try {
run();
} catch (const std::exception& e) {
print_exception(e);
}
}
Código completo:
#include <exception>
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <string>
void print_exception(const std::exception& ex, int stage = 0) {
std::cerr << std::string(stage, ' ') << "Encountered Exception: " << ex.what()
<< '\n';
try {
std::rethrow_if_nested(ex);
} catch (const std::exception& nestedException) {
print_exception(nestedException, stage + 1);
} catch (...) {
}
}
void open_file(const std::string& s) {
try {
std::ifstream file(s);
file.exceptions(std::ios_base::failbit);
} catch (...) {
std::throw_with_nested(std::runtime_error("Couldn't open " + s));
}
}
void run() {
try {
open_file("nonexistent.file");
} catch (...) {
std::throw_with_nested(std::runtime_error("run() failed"));
}
}
int main() {
try {
run();
} catch (const std::exception& e) {
print_exception(e);
}
}
Producción :
exception: run() failed
exception: Couldn't open nonexistent.file
exception: basic_ios::clear
--------------------------------
Process exited after 0.05326 seconds with return value 0
Press any key to continue . . .
Use el error de tiempo de ejecución para lanzar excepciones con el mensaje en C++
Las clases personalizadas se pueden usar para generar excepciones con un mensaje variable, junto con la ruta del archivo de origen y la línea donde se genera este error.
Este programa usa macros y clases personalizadas para generar un mensaje variable en la cadena explicativa usando std::runtime_error
.
Importar paquetes
Este programa requiere cuatro paquetes de importación, que son:
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
Clase pública
Este programa usa una clase constructora para lanzar excepciones con un mensaje variable y mostrar ese mensaje personalizado como una cadena explicativa cuando se llama al constructor público usando std::runtime_error
.
La primera línea del fragmento de código crea una clase my_exception
y un nuevo objeto runtime_error
. Junto a él, se crea un objeto de cadena msg
con alcance global, que se utilizará para pasar la variable explicativa cadena.
La clase constructora my_exception
se inicializa con tres parámetros: un objeto de cadena std
arg
que pasa la cadena explicativa, un objeto puntero *file
de tipo de datos char que almacena el nombre del archivo y una variable entera línea que almacena la línea donde se lanza la excepción.
Se crea un objeto de salida de cadena con std::ostringstream
para mostrar una salida cuando se llama a este objeto. Por último, este objeto se almacena dentro de la variable msg
.
El destructor ~my_exception()
devuelve la variable msg
como una cadena terminada en nulo usando return msg.c_str();
.
class my_exception : public std::runtime_error {
std::string msg;
public:
my_exception(const std::string &arg, const char *file, int line)
: std::runtime_error(arg) {
std::ostringstream o;
o << file << ":" << line << ": " << arg;
msg = o.str();
}
~my_exception() throw() {}
const char *what() const throw() { return msg.c_str(); }
};
Macros y lanzamiento de excepciones
Aquí, una macro se define usando #define throw_line(arg)
. Llamar a throw_line()
lanzará my_exception(arg, __FILE__, __LINE__)
.
El método void f()
llama a la macro throw_line
y pasa el mensaje Oh no!
.
#define throw_line(arg) throw my_exception(arg, __FILE__, __LINE__);
void f() { throw_line("Oh no!"); }
Método principal
El método principal lanzará excepciones con un mensaje variable llamando al método f()
dentro del bloque try
. Esto pasa el bloque de mensajes al método my_exception
.
Dentro del bloque catch
, se crea un objeto runtime_error
ex
, que llamará a la cadena explicativa usando ex.what()
.
Cuando se llama a la cadena explicativa, se llama al objeto ostream
dentro del constructor my_exception
y devuelve el nombre del archivo y la línea de error junto con el mensaje variable.
int main() {
try {
f();
} catch (const std::runtime_error &ex) {
std::cout << ex.what() << std::endl;
}
}
Código completo:
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
class my_exception : public std::runtime_error {
std::string msg;
public:
my_exception(const std::string &arg, const char *file, int line)
: std::runtime_error(arg) {
std::ostringstream o;
o << file << ":" << line << ": " << arg;
msg = o.str();
}
~my_exception() throw() {}
const char *what() const throw() { return msg.c_str(); }
};
#define throw_line(arg) throw my_exception(arg, __FILE__, __LINE__);
void f() { throw_line("Oh no!"); }
int main() {
try {
f();
} catch (const std::runtime_error &ex) {
std::cout << ex.what() << std::endl;
}
}
Producción :
D:\c++\std-exceptions\8.cpp:23: Oh no!
--------------------------------
Process exited after 0.006875 seconds with return value 0
Press any key to continue . . .
Conclusión
Este artículo explica las diversas formas de lanzar excepciones con un mensaje variable y luego mostrar el mensaje cuando se lanzan excepciones.
Esperamos que este artículo le haya ayudado a aprender a lanzar excepciones con un mensaje variable, y podrá usarlo en escenarios de la vida real.