ProgramaciónDesarrollador C++, Programador de sistemas

Hable sobre el mecanismo operator new/operator delete en C++. ¿Cómo se diferencian de new/delete, cuándo y por qué se sobrescriben las funciones de operador en clases de usuario?

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

En C++, operator new y operator delete son funciones de asignación y liberación de memoria que se llaman al crear y eliminar objetos a través de los operadores new y delete. Por defecto, utilizan el asignador estándar, pero en una clase se pueden sobrecargar para tener un control más fino sobre la asignación de memoria.

  • operator new asigna un bloque de memoria "crudo", sin llamar al constructor.
  • Después de la asignación de memoria, se llama automáticamente al constructor del objeto.
  • operator delete libera la memoria después de que se complete el destructor del objeto.

Uso (versiones global y local):

  • La versión global se aplica por defecto (por ejemplo, al usar new int).
  • Al sobrescribir un operator new específico en la clase, se puede optimizar el manejo de la memoria para objetos de esa clase (por ejemplo, grupo de objetos, seguimiento, reutilización de bloques).

Ejemplo de sobrecarga de operator new/operator delete:

#include <iostream> class TrackAlloc { public: void* operator new(size_t size) { std::cout << "TrackAlloc::new para " << size << " bytes "; return ::operator new(size); } void operator delete(void* ptr) { std::cout << "TrackAlloc::delete "; ::operator delete(ptr); } };

Matices:

  • Llamar a nuevos/eliminar objetos con argumentos (placement new) requiere una sobrecarga adicional.
  • Los operadores sobrescritos solo se llaman al crear/eliminar objetos de la clase, no para new[]/delete[]. Para ellos se pueden sobrecargar versiones separadas operator new[]/delete[].
  • Las manipulaciones de memoria son peligrosas: se requiere un manejo adecuado de excepciones.

Pregunta capciosa.

"¿Qué sucederá si se sobrescribe el operador new en la clase y luego se crea un objeto a través de una variable de clase derivada? ¿Qué versión de operator new se llamará?"

Respuesta: Se llamará al operator new de la clase desde la cual se está creando el objeto. Si la clase derivada no tiene implementado operator new, se intentará encontrar la versión adecuada en la clase base o la versión global.

Ejemplo:

struct Base { void* operator new(size_t s) { std::cout << "Base new "; return ::operator new(s); } }; struct Derived : Base {}; Derived* p = new Derived; // ¡Llamará a Base::operator new!

Ejemplos de errores reales debido al desconocimiento de los matices del tema.


Historia

Los desarrolladores sobrescribieron operator new/ delete sin soporte para un manejo adecuado de excepciones. Al lanzar una excepción dentro del constructor, la memoria no se liberaba, lo que provocaba fugas.


Historia

Implementaron incorrectamente operator new[] y operator delete[]: para la clase que contenía arreglos, la nueva implementación no se llamaba, se utilizaban las versiones por defecto, lo que provocaba una desincronización en la lógica de asignación y liberación de memoria.


Historia

La sobrescritura del operator new global afectó el funcionamiento de bibliotecas de terceros: todos los objetos (incluidos temporales y de STL) comenzaron a asignarse a través del asignador registrado, lo que ralentizó drásticamente el núcleo de la aplicación.