2009-09-25 7 views
12

Ho una classe che richiede un costruttore di copia e un operatore di assegnazione non predefinito (contiene elenchi di puntatori). Esiste un modo generale per ridurre la duplicazione del codice tra il costruttore di copie e l'operatore di assegnazione?Riduzione della duplicazione del codice tra operator = e il costruttore di copie

+2

penso che dovresti essere in grado di chiamare il costruttore di copie all'interno dell'operatore = –

+0

Alcune risposte sono qui: http://stackoverflow.com/questions/1457842/is-this-good-code-copy-ctor-operator –

risposta

16

Non c'è "via generale" per la scrittura di costruttori di copia personalizzati e operatori di assegnazione che funziona in tutti i casi. Ma c'è un idioma chiamato "dalla duplicazione & -swap":

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

    void swap(myclass & with); 

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

    ... 
}; 

E 'utile in molti (ma non tutti) le situazioni. A volte puoi fare di meglio. Un vettore o una stringa potrebbe avere un incarico migliore che riutilizza la memoria allocata se fosse abbastanza grande.

+2

+1 - riassunto buono e conciso di copy-swap penso. Buona idea anche sul riutilizzo dello spazio di archiviazione. –

+2

Si potrebbe voler indicare la sottigliezza qui tra il proprio operatore = e il più costante const myclass & operator = (const myclass & other); – Bill

+1

Lo swap() dovrebbe probabilmente essere contrassegnato come notro. Idem sul commento di Bills. Qualche altra esplosione sarebbe carina. –

15

Calcolare il codice comune per una funzione membro privata. Un semplice (piuttosto artificiosa) Esempio:

#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: questo è quasi sempre il modo migliore per gestire la duplicazione del codice all'interno di una classe. –

+3

perdita di memoria! MakeDeepCopy ignora la possibilità del nome che punta già alla memoria allocata. – sellibitze

+4

Ma è un peccato che il costruttore di copie non possa usare gli inizializzatori dei membri, in questo modo ... – xtofl

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

e implementare uno specialista std::swap<> (My &, My &).

+1

Questo è il modo in cui dovrebbe apparire copy - & - swap. Stai creando esplicitamente una copia che altrimenti potrebbe essere eliminata. C'è un grande articolo a riguardo qui: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ – sellibitze

+3

Come nota Dave, alexandrescu ha già scoperto circa 6 anni fa: http : //www.ddj.com/cpp/184403855. Interessante anche leggere! –

+1

errm, per inciso il poster è anche chiamato Dave. Mi dispiace per la confusione - intendevo Dave Abrahams di cpp-next :) –

2

Come già sottolineato da alcuni manifesti, avere operatore = creare un nuovo oggetto con il costruttore di copia e quindi utilizzare lo swap è la tecnica comune utilizzata per non dover replicare il codice in operator =.

Detto questo, voglio sottolineare un pro e un contro di questa tecnica per aiutarti a decidere se è appropriato.

Pro - eccezione sicurezza

Se l'oggetto non ha i requisiti delle risorse che potrebbero causare un tiro e assumendo che di swap non buttare, questa tecnica fornisce la forte garanzia di sicurezza rispetto alle eccezioni (sia l'oggetto che viene assegnato a ha assunto il valore dell'altro oggetto o è invariato).

Con - risorsa impronta

Un problema con questa tecnica è che richiede un nuovo oggetto completo deve essere creato prima di quello vecchio viene rilasciato. Se il tuo oggetto richiede molte risorse, questo può essere un problema.