Operador delete

Revisión del 16:50 6 jul 2019 de Javiermartin jc (discusión | contribuciones) (Texto reemplazado: «<div align="justify">» por «»)
(dif) ← Revisión anterior | Revisión actual (dif) | Revisión siguiente → (dif)
Operador delete
Información sobre la plantilla
Concepto:El operador delete ofrece una desasignación dinámica de memoria, desasignando un bloque previamente asignado con new. Es similar pero superior a la función free de la Librería Estándar.

Operador delete. Los operadores delete y delete[] sirven respectivamente para destruir los objetos creados con new y new[], volviendo a dejar la memoria asignada a disposición del gestor de memoria del compilador. Los objetos creados con new deben ser destruidos necesariamente con delete, y que las matrices creadas con new[ ] deben ser borradas con delete[ ].

El operador delete

El operador delete (palabra clave) ofrece una desasignación dinámica de memoria, desasignando un bloque previamente asignado con new. Es similar pero superior a la función free de la Librería Estándar. Este operador debe utilizarse para remover toda la memoria previamente asignada con new; de no hacerse así, puede producirse un agotamiento de la memoria. Sin embargo no puede usarse para desasignar memoria previamente asignada con malloc. Es muy frecuente encontrar a este operador en destructores de clases, a fin de desasignar el espacio de los objetos cuando dicho espacio fue asignado con el operador new en el constructor.

Sintaxis

<::> delete <cast-expression>
<::> delete [ ] <cast-expression>  // para matrices
delete <array-name> [ ];           // para matrices

Ejemplos

char* p;
void func() {
  p = new char[10];     // asigna espacio para 10 char
  ...
  delete[] p;           // desasigna el espacio anterior
}

void* sptr;            // puntero genérico
(std::string*) sptr = new std::string[10];    // L.2
...
delete [] (std::string*) sptr;                // L.4

std::string es un calificador de tipo; se refiere a un objeto tipo string. Observe que L.2 realiza la asignación de espacio para el objeto (en este caso el contenedor está previsto para 10 caracteres) y además realiza un modelado sobre el puntero genérico sptr para adecuarlo al tipo devuelto por new. Finalmente, la sentencia L4 restituye el espacio reservado en L2.

Precauciones con delete

Cuando este operador se utiliza con punteros (como en el ejemplo), es un gran error volver a utilizar la misma sentencia con el mismo puntero (esto puede suceder por error). Considere el siguiente código:

delete ptr;
...
delete ptr;       // Error!!

Si las sentencias entre ambos deleteno modifican el valor del puntero ptr, puede producirse un error grave. Recuerde que la desasignación de la memoria señalada por ptr no implica alteración del Rvalue(ptr), así que lo mejor es hacer:

delete ptr;
ptr = 0;
...
delete ptr;       // Ahora sin riesgo!

Ya que por definición, el operador delete sobre un puntero nulo es una operación nula. Por esta razón, si se sobrecarga este operador, puede ser buena idea incluir en la función asignar cero al puntero:

tipoX::operator delete(ptr) {
  ...
  ptr = NULL;
}

Idéntica situación de riesgo se presenta cuando más de un puntero señala al mismo objeto:

C* cptr = new C;
C* dptr = cptr;
...
delete cptr;
delete dptr;        // Error!!

También cuando el puntero inicial ha sido modificado inadvertidamente:

char* p = new char[10];
...
p++;
...
delete[] p;         // Error!!

Es un error aplicar el operador delete a un puntero cuyo valor no haya sido previamente asignado por new. Por ejemplo:

void (* fptr)();
void func() {...}
const int ki;
const int* kptr;
...
ftpr = func;
delete fptr;        // Error!! intento de borrar puntero a función
kptr = &ki;
delete kptr;        // Error!! intento de borrar puntero a constante

Sobrecarga de los operadores delete/delete[ ]

No es posible sobrecargar la versión global de las funciones-operador ::operator delete() y ::operator delete()[ ]. Sin embargo es posible ocultarlas con versiones globales propias, aunque solo es posible definir una versión global de cada operador en cada aplicación. Estas versiones deben devolver void, y su primer argumento debe ser un puntero-a-void (void*). Se admite un segundo argumento opcional de tipo size_t para indicar la cantidad de espacio a liberar. Por consiguiente, el prototipo puede ser algo así:

void delete(void* Type_ptr [, size_t Type_size]) { ... };
void delete[](void* Type_ptr [, size_t Type_size]) { ... };

Las clases C que tengan su propia versión de los operadores new() y/o new()[], pueden tener también sus propias versiones sobrecargadas de los operadores delete y delete[]. Para ello se definen versiones propias de las funciones-operador C::operator delete[]() y C::operator delete() según los siguientes prototipos: void operator delete(void* Type_ptr [, size_t Type_size]); void operator delete[](size_t Type_ptr [, size_t Type_size]);

  • Type_ptr es un puntero-al-objeto (instancia de clase) que se desea destruir.
  • Type_size es un argumento opcional tipo size_t indicando el tamaño del objeto.

El operador delete con matrices

Para borrar matrices debe utilizarse la segunda forma de la sintaxis: delete [] <array-name>;

Ejemplo

for (i = 0; i < fil; i++)   // Paso 1: Borrar columnas
 delete [] x[i];
delete [] x;                // paso 2: borrar filas

Estas expresiones el primer par de llaves [ ] están vacías, es la forma de indicar al operador delete que se trata del espacio de una matriz. Como puede verse en la segunda línea, opcionalmente puede indicarse un elemento a borrar. En el capítulo dedicado a la Inicialización indirecta de matrices puede encontrarse una completa descripción y ejemplos del proceso para crear y destruir matrices en el montón, lo que supone la utilización de los operadores new y delete.

Véase también

Fuente