nuevo y eliminar (C ++) - new and delete (C++)


En el lenguaje de programación C ++ , new y delete son un par de construcciones de lenguaje que realizan la asignación dinámica de memoria , la construcción de objetos y la destrucción de objetos .

Descripción general

Excepto por un formulario llamado "colocación nueva" , el nuevo operador denota una solicitud de asignación de memoria en el montón de un proceso . Si hay suficiente memoria disponible, new inicializa la memoria, llamando a los constructores de objetos si es necesario, y devuelve la dirección a la memoria recién asignada e inicializada. Una nueva solicitud, en su forma más simple, tiene el siguiente aspecto:

p = new T;

donde p es un puntero previamente declarado de tipo T (o algún otro tipo al que se pueda asignar un puntero T , como una superclase de T ). El constructor predeterminado para T , si lo hay, se llama para construir una instancia de T en el búfer de memoria asignado.

Si no hay suficiente memoria disponible en la tienda gratuita para un objeto de tipo T , la nueva solicitud indica falla al lanzar una excepción de tipo std :: bad_alloc . Esto elimina la necesidad de verificar explícitamente el resultado de una asignación.

La contraparte de desasignación de new es delete , que primero llama al destructor (si lo hay) en su argumento y luego devuelve la memoria asignada por new a la tienda libre. Cada llamada a new debe coincidir con una llamada a eliminar ; si no lo hace, se producirán pérdidas de memoria .

La nueva sintaxis tiene varias variantes que permiten un control más preciso sobre la asignación de memoria y la construcción de objetos. Se usa una sintaxis similar a una llamada a función para llamar a un constructor diferente al predeterminado y pasarle argumentos, por ejemplo,

p = new T(argument);

llama a un constructor T de un solo argumento en lugar del constructor predeterminado al inicializar el búfer recién asignado.

Una variante diferente asigna e inicializa matrices de objetos en lugar de objetos individuales:

p = new T [N];

Esto solicita un búfer de memoria del almacén libre que sea lo suficientemente grande como para contener una matriz contigua de N objetos de tipo T , de forma contigua, y llama al constructor predeterminado en cada elemento de la matriz.

La memoria asignada con el nuevo [] debe desasignarse con el operador de eliminación [] , en lugar de eliminar . El uso de la forma inapropiada da como resultado un comportamiento indefinido . No es necesario que los compiladores de C ++ generen un mensaje de diagnóstico por utilizar el formulario incorrecto.

El estándar C ++ 11 especifica una sintaxis adicional,

p = new T[N] {initializer1, ..., initializerN};

que inicializa cada p [ i ] al inicializador i + 1 .

Manejo de errores

Si new no puede encontrar suficiente memoria para atender una solicitud de asignación, puede informar su error de tres formas distintas. En primer lugar, el estándar ISO C ++ permite a los programas registrar una función personalizada llamada new_handler con el tiempo de ejecución de C ++ ; si lo hace, entonces se llama a esta función cada vez que un nuevo encuentra un error. El new_handler puede intentar hacer más memoria disponible, o terminar el programa si no puede.

Si no se instala new_handler , new en su lugar lanza una excepción de tipo std :: bad_alloc . Por lo tanto, el programa no necesita verificar el valor del puntero devuelto, como es el hábito en C ; si no se lanzaba ninguna excepción, la asignación se realizaba correctamente.

El tercer método de manejo de errores lo proporciona la forma variante new (std :: nothrow) , que especifica que no se debe lanzar ninguna excepción; en su lugar, se devuelve un puntero nulo para señalar un error de asignación.

Sobrecarga

El nuevo operador se puede sobrecargar para que tipos específicos (clases) utilicen algoritmos de asignación de memoria personalizados para sus instancias. Por ejemplo, la siguiente es una variante del patrón singleton donde la primera nueva llamada Singleton asigna una instancia y todas las llamadas posteriores devuelven esta misma instancia:

#include <cstdlib>
#include <cstddef>

class Singleton {
public:
  static void* operator new(std::size_t size) {
    if (!instance) {
      instance = std::malloc(size);
    }
    refcount++;
    return instance;
  }

  static void operator delete(void*) noexcept {
    if (--refcount == 0) {
      std::free(instance);
      instance = nullptr;
    }
  }

private:
  static void* instance = nullptr;
  static std::size_t refcount = 0;
};

Esta característica estuvo disponible desde el principio de la historia de C ++, aunque el mecanismo de sobrecarga específico cambió. Se agregó al lenguaje porque los programas C ++ orientados a objetos tendían a asignar muchos objetos pequeños con nuevos , que usaban internamente el asignador C (ver § Relación con malloc y free ); que, sin embargo, se optimizó para las asignaciones más pequeñas y más grandes realizadas por los programas C típicos. Stroustrup informó que en las primeras aplicaciones, la función C malloc era "el cuello de botella de rendimiento más común en sistemas reales", y los programas dedicaban hasta el 50% de su tiempo a esta función.

void *operator new(size_t size)

Se llama a la construcción del lenguaje C ++ que solo asigna memoria . Es utilizado por nuevos en la fase de asignación. Se puede anular por clase o globalmente para definir un asignador de memoria específico. void *operator new(size_t size)

Relación con malloc y free

Dado que C ++ estándar subsume la biblioteca estándar de C , las rutinas de asignación de memoria dinámica de C malloc , calloc , realloc y free también están disponibles para los programadores de C ++. Se desaconseja el uso de estas rutinas para la mayoría de los usos, ya que no realizan la inicialización y destrucción de objetos. new y delete fueron, de hecho, introducidos en la primera versión de C ++ (entonces llamado " C con clases ") para evitar la necesidad de inicialización manual de objetos.

A diferencia de las rutinas de C, que permiten aumentar o reducir una matriz asignada con realloc , no es posible cambiar el tamaño de un búfer de memoria asignado por new [] . En cambio, la biblioteca estándar de C ++ proporciona una matriz dinámica (colección) que se puede ampliar o reducir en su clase de plantilla std :: vector .

El estándar C ++ no especifica ninguna relación entre new / delete y las rutinas de asignación de memoria C, pero new y delete se implementan típicamente como envoltorios alrededor de malloc y free . Mezclar las dos familias de operaciones, por ejemplo, libre de 'ing nueva ' memoria Ly asignado o borrado 'ing malloc ' memoria d, provoca un comportamiento indefinido y en la práctica puede dar lugar a diversos resultados catastróficos, tales como falta de liberación cerraduras y por lo tanto un punto muerto .

Ver también

Referencias