ProgramaciónDesarrollador C++

Describe las reglas de tres y cinco (Rule of Three / Rule of Five) en C++11 y su importancia en el diseño de clases.

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

Regla de tres: si una clase gestiona un recurso (por ejemplo, memoria), al implementar explícitamente uno de los siguientes métodos, es necesario implementar también los demás:

  • Destructor
  • Constructor de copia
  • Operador de asignación de copia

C++11: Regla de cinco – se añadieron operaciones de movimiento:

  • Constructor de movimiento
  • Operador de asignación de movimiento

La violación de esta regla conduce a errores en la gestión de recursos, como la eliminación doble o fugas de memoria.

Ejemplo de código:

class Buffer { char* data; public: Buffer(size_t sz) : data(new char[sz]) {} ~Buffer() { delete[] data; } Buffer(const Buffer& other) : data(new char[strlen(other.data)+1]) { strcpy(data, other.data); } Buffer& operator=(const Buffer& other) { if (&other != this) { delete[] data; data = new char[strlen(other.data)+1]; strcpy(data, other.data); } return *this; } // semántica de movimiento en C++11+: Buffer(Buffer&& other) noexcept : data(other.data) { other.data = nullptr; } Buffer& operator=(Buffer&& other) noexcept { if (&other != this) { delete[] data; data = other.data; other.data = nullptr; } return *this; } };

Pregunta capciosa.

¿Es suficiente implementar solo el destructor si la clase gestiona un puntero?

No. Sin operaciones de copia y movimiento, al copiar habrá eliminación doble de memoria. Por ejemplo:

Buffer a(10); Buffer b = a; // b y a eliminarán el mismo puntero!

Ejemplos de errores reales debido al desconocimiento de las sutilezas del tema.


Historia

En la plataforma de agregación de datos para telecomunicaciones, todas las clases solo implementaron el destructor. Después de la refactorización de la estructura, hubo fallos masivos por eliminación doble: la copia de objetos producía comportamientos aleatorios.


Historia

En el proyecto de un juego móvil, olvidaron implementar el constructor de movimiento para la clase contenedora del búfer. Al mover, el objeto se copiaba, lo que causaba copias innecesarias de datos y caídas de rendimiento.


Historia

En la biblioteca de serialización de estructuras de datos, al regresar un objeto de una función, se devolvía un objeto temporal, y el constructor de copia hacía una copia superficial del puntero. Esto provocó numerosas fugas, que solo se manifestaron meses después de su funcionamiento.