ProgramaciónDesarrollador C++

¿Qué sucede al pasar un objeto de una clase por valor a una función y qué aspectos problemáticos se deben tener en cuenta al implementar el constructor de copia?

Supere entrevistas con el asistente de IA Hintsage

Respuesta

Al pasar un objeto por valor a una función en C++ se crea una copia del objeto utilizando el constructor de copia. Si se ha definido un constructor de copia personalizado en la clase, se invoca para inicializar el objeto temporal argumento de la función. Si no está definido, se utiliza el compilador por defecto, que realiza una copia a nivel de bits (shallow copy).

Aspectos problemáticos:

  • Si la clase gestiona recursos (por ejemplo, tiene punteros desnudos), el constructor de copia generado por defecto puede llevar a errores de liberación doble de memoria y filtraciones.
  • Es necesario asegurarse de que el constructor de copia copie correctamente los recursos (normalmente deep copy).

Ejemplo:

class StringWrapper { char* data; public: StringWrapper(const char* str) { data = new char[strlen(str) + 1]; strcpy(data, str); } // Error: shallow copy StringWrapper(const StringWrapper& other) : data(other.data) {} ~StringWrapper() { delete [] data; } }; void foo(StringWrapper s) { // ... } int main() { StringWrapper s1("hello"); foo(s1); // UB!!! return 0; }

Pregunta capciosa

"¿Qué pasará si se define el constructor de copia en una clase con un puntero de esta manera: MyClass(const MyClass &other) : data(other.data) {}? ¿Qué consecuencias tiene esto?"

Respuesta correcta: Tal constructor de copia creará un objeto con un puntero a la misma región de memoria que el objeto copiado. Al destruir ambos objetos, la memoria será liberada dos veces (double free), lo que conduce a comportamientos indefinidos. Se debe implementar deep copy:

MyClass(const MyClass &other) { data = new int(*other.data); }

Ejemplos de errores reales debido a la falta de conocimiento de los matices del tema


Historia

En un gran proyecto servidor se utilizaron contenedores de objetos con un "arreglo" desnudo interno y un constructor de copia estándar (shallow copy). Al pasar objetos por valor, ocurría un double free y fallos de la aplicación, detectados solo en producción.


Historia

En una antigua biblioteca de C++ para trabajar con imágenes, el constructor de copia no copiaba el búfer gráfico, lo que provocaba que al cambiar una copia de la imagen, se modificara la otra y generara errores inesperados en la interfaz.


Historia

Al devolver un objeto por valor desde una función en uno de los sistemas internos de almacenamiento de contraseñas, los datos se limpiaban al destruir el objeto temporal (shallow copy), lo que resultaba en que el objeto real almacenaba un puntero nulificado, y la filtración se descubrió accidentalmente durante una auditoría de seguridad.