Created: 2025-05-14 mié 00:19
Simply put, an Error is a bug in the application. An Exception is a bug in the input to the application. The former is not recoverable, the latter is.
– Walter Bright, D Language creator.
assert
.assert(condition)
es una macro que evalúa un predicado, si este es
cierto
, el código sigue ejecutándose, pero si es falso
se aborta
la ejecución de la aplicación inmediatamente en ese punto,
informándonos de dónde ha fallado la aserción y por qué motivo.
Para hacer uso de assert
desde C++ incluiremos la cabecera
cassert
.
#include <iostream>
#include <cassert>
double fastSqrt (double x) {
assert(x >= 0.0 );
...
assert(x == (result*result));
return result;
}
if
, ¿no?Por ejemplo, así:
#include <iostream>
double fastSqrt (double x) {
if (not (x >= 0.0) ) ... ;
...
if (not (x == (result*result)) ... ;
return result;
}
assert
?NDEBUG
,
p.e. así: g++ -DNDEBUG example.cc
.try
throw
catch
Un ejemplo muy sencillo:
#include <iostream>
double f(double d) {
if (d > 1e7)
throw std::overflow_error("too big");
else
return d;
}
int main() {
try {
std::cout << f(1e10) << '\n';
} catch (const std::overflow_error& e) {
std::cout << e.what() << '\n';
}
}
char
, int
, etc, pero también datos más complejos como objetos.void f() throw(int);
void f() throw();
void f() noexcept;
o void f() noexcept(true);
std::unexpected()
.unexpected
llama a std::terminate
y el programa acaba.Se puede cambiar la función a la que llama, p.e.:
#include <exception> // std::set_unexpected
void myunexpected () {
std::cerr << "unexpected called\n";
}
int main() {
std::set_unexpected(myunexpected);
...
}
noexcept
, se asume que puede lanzar cualquier excepción.A un bloque try le podemos asociar varios bloques catch:
int main (void) {
std::set_unexpected (myunexpected);
try {
myfunction();
}
catch (int) { std::cerr << "caught int\n"; }
catch (...) { std::cerr << "caught some other exception type\n"; }
return 0;
}
IMPORTANTE: Los bloques catch se evalúan por orden, por tanto si el tipo de un catch concuerda con el tipo de la excepción lanzada, entonces se trata en ese catch.
class ExceptionBase {...};
class ExceptionDerived : public ExceptionBase {...};
...
try {
f (); // throws ExceptionDerived
}
catch (ExceptionBase& eb) {...} // <-- se captura aquí
catch (ExceptionDerived& ed) {...}
catch (...)
Una excepción se puede relanzar:
try {
f (); // throws ExceptionDerived
}
catch (ExceptionBase& eb) { throw; } // <-- se relanza aquí
stdexcept
(la cual incluye a
exception
).exception
y derivadas de
ella como logic_error
, length_error
, etc…runtime_error( const std::string& what_arg );
.exception
:virtual const char* what() const noexcept;
class file { // https://es.wikipedia.org/wiki/RAII
public:
file (const char* filename) : file_ (std::fopen(filename, "w+")) {
if (!file_) {
throw std::runtime_error ("Error al abrir un archivo.");
}
}
~file() {
if (std::fclose(file_)) {
throw std::runtime_error ("Error al cerrar un archivo.");
}
}
void write (const char* str) {...}
}
void main () {
////////////////////////////////////////////////////////
// Abrimos el archivo, estamos adquiriendo un recurso //
////////////////////////////////////////////////////////
file logfile ("registro_de_incidencias.txt");
logfile.write ("¡Hola, registro!");
} // <- Al salir de ámbito, en el destructor de logfile se cierra el fichero
Ya no será necesario ocuparse de la liberación de memoria reservada dinámicamente, juzga tú mismo:
// compilar con C++11
#include <memory>
#include <iostream>
int main () { // Compila y ejecuta con valgrind, no
// creeras lo que ven tus ojos...
std::unique_ptr<int[]> pe (new int[1024]);
// compara con una línea como esta:
// int* pe = new int[1024];
return 0;
}
finally
.Los bloques finally se ejecutan siempre, tanto si se sale del bloque try de forma correcta o por que se ha lanzado una excepción y hemos entrado en un catch.
try { ... }
catch (et1) {...}
catch (et2) {...}
finally { ... }
En Rust existe este enumerado:
enum Result<T,E> {
Ok(T), // Constructor de Result<T> a partir de un tipo T, resultado correcto
Err(E), // Constructor de Result<E> a partir de un tipo E, error
}
Ok(T)
y Err(E)
como sendas funciones que crean un
dato de tipo Result
a partir de un dato de tipo:
T
si hay resultado, T
es el tipo del resultadoE
si se produce un error, E
es el tipo del errorfn mayor_o_menor_0 (n: i32) -> Result<bool, &'static str> {
if n < 0 || n > 0 {
Ok(true)
} else {
Err("n es 0")
}
}
fn main() {
let r = mayor_o_menor_0(0);
assert!(r.is_err())
}