13.3.2. Cuando se supera el espacio de almacenamiento

¿Qué ocurre cuando 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. Para ello comprueba si un determinado puntero a función es nulo, si no lo es, se efectúa la llamada a la función a la que apunta.

El comportamiento por defecto del manejador de errores de new es disparar 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 manejador de new-handler por defecto consiste en incluir el archivo 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.7. C13/NewHandler.cpp


La función a instalar debe retornar void y no tomar argumentos. El bucle while seguirá pidiendo bloques de int hasta consumir la memoria libre disponible, sin hacer nada con ellos. Justo a 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á la llamada al manejador de new. Si se desea que se produzca dicha llamada será necesario que lo haga 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 este no es un trabajo adecuado para programadores noveles.