2009-09-25 11 views
12

Tengo una clase que requiere un constructor de copia no predeterminado y un operador de asignación (contiene listas de punteros). ¿Hay alguna forma general de reducir la duplicación de código entre el constructor de copia y el operador de asignación?Reducción de la duplicación de código entre operator = y el constructor de copia

+2

creo que debería poder llamar al constructor de copias dentro del operador = –

+0

Algunas respuestas están aquí: http://stackoverflow.com/questions/1457842/is-this-good-code-copy-ctor-operator –

Respuesta

16

No hay "de manera general" para la escritura de constructores de copia de encargo y operadores de asignación que funciona en todos los casos. Pero hay un idioma llamado "contra copias & -Swap":

class myclass 
{ 
    ... 
public: 
    myclass(myclass const&); 

    void swap(myclass & with); 

    myclass& operator=(myclass copy) { 
     this->swap(copy); 
     return *this; 
    } 

    ... 
}; 

Es útil en muchos (pero no todas) las situaciones. A veces puedes hacerlo mejor. Un vector o una cadena podría tener una asignación mejor, que reutiliza el almacenamiento asignado si era lo suficientemente grande.

+2

+1 - resumen bueno y concisa del cambio de copia, creo. También es una buena idea reutilizar el almacenamiento. –

+2

Es posible que desee señalar la sutileza aquí entre su operador = y el más estándar const myclass & operator = (const myclass & other); – Bill

+1

El intercambio() probablemente debería marcarse como nothrow. Ídem en el comentario de Bills. Un poco más de explicación sería agradable. –

15

Factoriza el código común para una función de miembro privado. Un simple (y no artificial) ejemplo:

#include <iostream> 

class Test 
{ 
public: 
    Test(const char* n) 
    { 
    name = new char[20]; 
    strcpy(name, n); 
    } 

    ~Test() 
    { 
    delete[] name; 
    } 

    // Copy constructor 
    Test(const Test& t) 
    { 
    std::cout << "In copy constructor.\n"; 
    MakeDeepCopy(t); 
    } 

    // Assignment operator 
    const Test& operator=(const Test& t) 
    { 
    std::cout << "In assignment operator.\n"; 
    MakeDeepCopy(t); 
    } 

    const char* get_name() const { return name; } 

private: 
    // Common function where the actual copying happens. 
    void MakeDeepCopy(const Test& t) 
    {   
    strcpy(name, t.name); 
    } 

private: 
    char* name; 
}; 

int 
main() 
{ 
    Test t("vijay"); 
    Test t2(t); // Calls copy constructor. 
    Test t3(""); 
    t3 = t2; // Calls the assignment operator. 

    std::cout << t.get_name() << ", " << t2.get_name() << ", " << t3.get_name() << '\n'; 

    return 0; 
} 
+1

+1: esta es casi siempre la mejor forma de manejar la duplicación de código dentro de una clase. –

+3

pérdida de memoria! MakeDeepCopy ignora la posibilidad de que el nombre ya esté apuntando a la memoria asignada. – sellibitze

+4

Pero es una pena que el constructor de copias no pueda usar los inicializadores de miembros, de esta manera ... – xtofl

6
My &My::operator = (My temp) // thanks, sellibitze 
{ 
    swap (*this, temp); 
    return *this; 
} 

e implementar un std::swap<> (My &, My &) especializada.

+1

Así es como debe verse copy & & swap. Está creando explícitamente una copia que, de otro modo, podría eludirse. Hay un excelente artículo al respecto aquí: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ – sellibitze

+3

Como Dave notó, alexandrescu ya encontró sobre esto hace 6 años: http : //www.ddj.com/cpp/184403855. Interesante leer también! –

+1

errm, por cierto, el cartel también se llama Dave. Lamento la confusión, me refiero a Dave Abrahams de cpp-next :) –

2

Como ya se ha señalado en bastantes pósters, tener operator = crear un nuevo objeto con el constructor de copia y luego usar swap es la técnica común utilizada para no tener que replicar el código en operator =.

Dicho esto, quiero señalar algunos pro y contra de esta técnica para ayudarlo a decidir si es apropiado.

Pro - excepción de seguridad

Si el objeto tiene necesidades de recursos que podrían causar un tiro y suponiendo que swap no arrojará, esta técnica proporciona la fuerte garantía de la seguridad de excepción (siendo asignado ya sea el objeto que ha adquirido el valor del otro objeto o no se modifica).

Con - recursos huella

Un problema con esta técnica es que requiere un nuevo objeto completo a crearse antes de liberar la antigua. Si su objeto requiere muchos recursos, esto puede ser un problema.

Cuestiones relacionadas