Hay un método llamado foo
que a veces devuelve el siguiente error:
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Abort
¿Hay alguna forma de que pueda usar un bloque try
-catch
para evitar que este error termine mi programa (todo lo que quiero hacer es devolver -1
)?
Si es así, ¿cuál es la sintaxis?
¿De qué otra forma puedo tratar con bad_alloc
en C++?
En general usted no puede, y no debería intentar, responder a este error. bad_alloc
indica que un recurso no puede ser asignado porque no hay suficiente memoria disponible. En la mayoría de los escenarios tu programa no puede esperar hacer frente a esto, y terminar pronto es el único comportamiento significativo.
Peor aún, los sistemas operativos modernos a menudo sobre-asignan: en tales sistemas, malloc
y new
pueden un puntero válido incluso si no queda suficiente memoria libre - std::bad_alloc
nunca será lanzado, o al menos no es una señal fiable de agotamiento de memoria. En cambio, los intentos de acceder a la memoria asignada resultarán en un fallo de segmentación, que no es capturable (puedes manipular la señal de fallo de segmentación, pero no puedes reanudar el programa después).
Lo único que se puede hacer cuando se captura std::bad_alloc
es quizás registrar el error, e intentar asegurar una terminación segura del programa liberando los recursos pendientes (pero esto se hace automáticamente en el curso normal del desenrollado de la pila después de que se lance el error si el programa usa RAII apropiadamente).
En ciertos casos el programa puede intentar liberar algo de memoria e intentarlo de nuevo, o usar memoria secundaria (= disco) en lugar de RAM pero estas oportunidades sólo existen en escenarios muy específicos con condiciones estrictas:
Es extremadamente raro que las aplicaciones tengan control sobre el punto 1 - las aplicaciones de espacio de usuario nunca lo tienen, es una configuración de todo el sistema que requiere permisos de root para cambiarla;
OK, asumamos que has arreglado el punto 1. Lo que puedes hacer ahora es, por ejemplo, utilizar una caché LRU para algunos de tus datos (probablemente algunos objetos de negocio particularmente grandes que pueden ser regenerados o recargados bajo demanda). A continuación, tienes que poner la lógica real que puede fallar en una función que soporte reintentos - en otras palabras, si se aborta, puedes simplemente relanzarla:
lru_cache<widget> widget_cache;
double perform_operation(int widget_id) {
std::optional<widget> maybe_widget = widget_cache.find_by_id(widget_id);
if (not maybe_widget) {
maybe_widget = widget_cache.store(widget_id, load_widget_from_disk(widget_id));
}
return maybe_widget->frobnicate();
}
...
for (int num_attempts = 0; num_attempts < MAX_NUM_ATTEMPTS; ++num_attempts) {
try {
return realizar_operación(widget_id);
} catch (std::bad_alloc const&) {
if (widget_cache.empty()) throw; // error de memoria en otro lugar.
widget_cache.remove_oldest();
}
}
// Maneja demasiados intentos fallidos aquí.
Pero incluso aquí, usar std::set_new_handler
en lugar de manejar std::bad_alloc
proporciona el mismo beneficio y sería mucho más simple.
Si estás creando una aplicación que hace controlar el punto 1, y estás leyendo esta respuesta, por favor envíame un email, tengo verdadera curiosidad por tus circunstancias.
Puede capturarla como cualquier otra excepción:
try {
foo();
}
catch (const std::bad_alloc&) {
return -1;
}
Lo que puedas hacer útilmente desde este punto depende de ti, pero es definitivamente factible técnicamente.
Yo no sugeriría esto, ya que bad_alloc
significa que estás sin memoria. Lo mejor sería darse por vencido en lugar de intentar recuperarla. Sin embargo aquí está la solución que usted está pidiendo:
try {
foo();
} catch ( const std::bad_alloc& e ) {
return -1;
}