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:
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; }
"¿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); }
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.