13.3.2. Cuando se agota la memoria

¿Qué ocurre cuando operator new() no puede encontrar un bloque contiguo suficientemente grande para alojar el objeto? En este caso se produce la llamada a una función especial: el manejador de errores de new o new-handler. O, mejor dicho, se comprueba un determinado puntero a función y, si no es nulo, se efectúa la llamada a la función a la que apunta.

El comportamiento por defecto del manejador de errores de new es lanzar una excepción, asunto del que se tratará en el Volumen 2. Si se piensa usar la asignación dinámica, conviene al menos reemplazar el manejador de errores de new por una función que advierta de la falta de memoria y fuerce la terminación del programa. De este modo, durante la depuración del programa, se podrá seguir la pista de lo sucedido. Para la versión final del programa, será mejor implementar una recuperación de errores más elaborada.

La forma de reemplazar el new-handler por defecto consiste en incluir el fichero new.h y hacer una llamada a la función set_new_handler() con la dirección de la función que se desea instalar:

//: C13:NewHandler.cpp
// Changing the new-handler
#include <iostream>
#include <cstdlib>
#include <new>
using namespace std;

int count = 0;

void out_of_memory() {
  cerr << "memory exhausted after " << count 
    << " allocations!" << endl;
  exit(1);
}

int main() {
  set_new_handler(out_of_memory);
  while(1) {
    count++;
    new int[1000]; // Exhausts memory
  }
} ///:~

Listado 13.8. C13/NewHandler.cpp


La función new-handler no debe tomar argumentos y su valor de retorno debe ser void. El bucle while seguirá pidiendo bloques de int hasta consumir la memoria libre disponible, sin hacer nada con ellos. En la siguiente llamada a new, no habrá espacio para asignar y se producirá la llamada al manejador de new.

Este comportamiento del new-handler está asociado al operator new(), de modo que si se sobrecarga operator new() (asunto que se trata en la siguiente sección), no se producirá por defecto la llamada al manejador de new. Si se desea que se produzca dicha llamada, será necesario escribir el código que la realice en el operator new() que substituya al original.

Por supuesto, es posible escribir manejadores new más sofisticados, incluso alguno que intente reclamar los bloques asignados que no se usan (conocidos habitualmente como recolectores de basura). Pero éste no es un trabajo adecuado para programadores noveles.