2010-02-27 20 views
5

Estoy leyendo C++ efectivo en el Ítem 5, mencionó dos casos en los que debo definir el operador de asignación de copia. El caso es una clase que contiene const y miembros de referencia.Cuando debería definir mi propio operador de copia y asignación

Le escribo para preguntar cuál es la regla general o el caso en el que debo definir mi propio constructor de copias y el operador de asignación?

También me gustaría saber cuándo debo definir mi propio constructor y destructor.

¡Muchas gracias!

+0

Por lo que yo entiendo (y actuar) - una buena práctica adicional (no retirar las otras respuestas aquí) será seguir "La regla de tres": https://stackoverflow.com/q/4172722/1971003 –

Respuesta

5

Debe crear su propia copia constructor y operador de asignación (y por lo general constructor por defecto también) cuando:

  • desea que el objeto que va a copiar o asignada, o puesto en un contenedor estándar tales como vector
  • El constructor de copia predeterminado y el operador de asignación no harán lo correcto.

Considere el siguiente código:

class A; // defined elsewhere 
class B { 
private: 
    A *my_very_own_a; 
}; 

Si deja que el constructor de copia automática de copiar un B, copiará el valor A * puntero a través de, por lo que los puntos de copia a la misma A instancia que el original. Pero parte del diseño de esta clase es que cada B tiene su propia A, por lo que el constructor de copias automático ha roto ese contrato. Por lo tanto, debe escribir su propio constructor de copia que creará un nuevo A para el nuevo B para señalar.

Sin embargo, tenga en cuenta este caso:

class A; // defined elsewhere 
class B { 
private: 
    A *shared_reference_to_a; 
}; 

Aquí cada B contiene un puntero a un A, pero el contrato de clase no exige una única A para cada B. Entonces, el constructor de copia automática podría hacer lo correcto aquí.

Tenga en cuenta que ambos ejemplos son el mismo código , pero con diferente intención del diseño.

Un ejemplo de la primera situación podría ser B == cuadro de diálogo, A == botón. Si crea una copia de un cuadro de diálogo, probablemente también necesite una copia de todos los contenidos.

Un ejemplo del segundo podría ser B == cuadro de diálogo, A == referencia al administrador de ventanas. Si copia un cuadro de diálogo, probablemente la copia exista en el mismo administrador de ventanas que el original.

3

El constructor de copia predeterminado a menudo causa que dos objetos "señalen" una parte común de la memoria. Esto se debe a que todo el constructor de copia predeterminado es una asignación de miembro. Así que si usted tiene un miembro de puntero, esto le puede meter en problemas

CClass::CClass(const CClass& src) 
    { 
     // these two point to the same place in memory now 
     // you really aught to allocate new memory 
     m_ptr = src.m_ptr; 

     // not a big deal for members that aren't "pointing" elsewhere 
     // this copy works great 
     m_int = src.m_int; 
    } 

Esencialmente no quiere terminar en una situación en la que dos casos son "apuntando a" el mismo lugar en la memoria. Esto puede suceder cuando tiene punteros como miembros que apuntan a memoria asignada dinámicamente. Esto también puede ocurrir con referencias, ambas haciendo referencia a algo que está fuera de la clase. Esto puede suceder con los manejadores de archivos, donde es posible que deba duplicar/volver a abrir un archivo nuevo.

De hecho, este último caso es probablemente el más fácil de conceptualizar. Imagina que tus 2 objetos C++ tenían un archivo de registro. Sin un constructor de copias que funcione correctamente, ambos podrían estar ingresando al mismo archivo. ¿Qué sucede si en las clases destructor, el archivo está cerrado? Bueno, entonces el segundo objeto C++ tendrá su archivo de registro cerrado por debajo de él. Una solución sería crear un constructor de copias que cree un nuevo archivo para la instancia recién construida. Entonces, cuando el primer objeto de C++ desaparece, no se lleva el archivo de registro del segundo objeto de C++. Tienen 2 archivos de registro independientes, no pueden interferir entre sí.

Este ejemplo se puede extender a la memoria dinámica. Sin un constructor de copia, solo tendrá 2 punteros apuntando a la misma dirección. Si el destructor de uno borra esa memoria, el otro podría no darse cuenta de que la memoria a la que apunta ha desaparecido. Igualmente importante, es probable que no desee que un objeto escriba en el miembro del otro objeto :).

Cuestiones relacionadas