2013-03-26 28 views
30

Perché compilatore C++ hanno più limitazione costruttori mossa generate automaticamente che sul generati automaticamente costruttore di copia o di operatore di assegnazione?predefinito mossa costruttore di default contro costruttore di copia di default vs. operatore di assegnamento

costruttori di spostamento generate automaticamente vengono generati solo se l'utente ha definito nulla (vale a dire: il costruttore, la copia, l'assegnazione, distruttore ..)

costruttore di copia o di operatore di assegnamento vengono generati solo se l'utente non ha definito rispettivamente copiare costruttore o operatore di assegnazione.

mi chiedo perché la differenza.

+1

Da un semplice punto di vista concettuale (attenzione, nessuna spiegazione tecnica), i due non sono uguali, ad es. ogni oggetto copiabile è mobile ma non viceversa. Lo spostamento è piuttosto un caso speciale di copia applicabile in determinate situazioni. Quindi ha senso che il loro comportamento di autogenerazione sia in qualche modo distorto. Ma lascio a qualcun altro la traduzione in standard tecnico con esempi appropriati. Altro che buona domanda, ovviamente. –

risposta

13

Credo compatibilità all'indietro gioca un ruolo importante qui. Se l'utente definisce una delle funzioni "Regola di tre" (copy ctor, copy assignment op, dtor), si può presumere che la classe esegua una gestione interna delle risorse. Definire implicitamente un costruttore di mosse potrebbe improvvisamente rendere invalida la classe quando compilata in C++ 11.

Considerate questo esempio:

class Res 
{ 
    int *data; 

public: 
    Res() : data(new int) {} 

    Res(const Res &arg) : data(new int(*arg.data)) {} 

    ~Res() { delete data; } 
}; 

Ora, se un costruttore di default mossa è stata generato per questa classe, la sua invocazione porterebbe ad una doppia eliminazione di data.

Come per l'operatore di assegnazione spostamento che impedisce le definizioni predefinite del costruttore di spostamento: se l'operatore di assegnazione spostamento fa qualcosa di diverso da quello predefinito, è molto probabile che sia errato utilizzare il costruttore di spostamento predefinito. È solo la "Regola del tre"/"Regola dei cinque" in vigore.

9

quanto ne so, questo è perché di compatibilità verso il basso. Considera le classi scritte in C++ (prima di C++ 11) e cosa succederebbe se C++ 11 iniziasse a generare automaticamente i sensori di movimento in parallelo con i duplicatori di copia esistenti o in generale con qualsiasi altro ctor. Romperebbe facilmente il codice esistente, bypassando il copy-ctor che l'autore di quella classe ha scritto. Quindi, le regole per generare un agente di movimento in cui sono predisposte si applicano solo ai casi "sicuri".

Ecco l'articolo di Dave Abrahams su why implicit move must go, che alla fine ha portato alle attuali regole del C++ 11.

e questo è un esempio di come fallirebbe:

// NOTE: This example assumes an implicitly generated move-ctor 

class X 
{ 
private:  
    std::vector<int> v; 

public: 
    // invariant: v.size() == 5 
    X() : v(5) {} 

    ~X() 
    { 
     std::cout << v[0] << std::endl; 
    } 
}; 

int main() 
{ 
    std::vector<X> y; 

    // and here is where it would fail: 
    // X() is an rvalue: copied in C++03, moved in C++0x 
    // the classes' invariant breaks and the dtor will illegally access v[0]. 
    y.push_back(X()); 
} 
+0

+1 per l'articolo! –

9

Quando C++ è stato creato, è stato deciso che costruttore di default, costruttore di copia, assegnazione operatore e distruttore verrebbero generati automaticamente (a meno che non in dotazione). Perché ? Perché i compilatori C++ dovrebbero essere in grado di compilare (la maggior parte) codice C con semantica identica, ed è così che struct funziona in C.

Tuttavia, è stato successivamente notato che ogni volta che un utente scrive un distruttore personalizzato, probabilmente ha bisogno di scrivere un anche operatore di copia/costruttore di copia personalizzato; questo è noto come Rule of Big Three. Con il senno di poi, possiamo vedere che si sarebbe potuto specificare che il generatore di copia/costruttore/distruttore generato sarebbe stato generato solo se nessuno dei 3 fosse stato fornito dall'utente e avrebbe aiutato a catturare molti bug. .. e mantengono comunque la retrocompatibilità con C.

Pertanto, con l'arrivo del C++ 11, è stato deciso che questa volta le cose sarebbero andate bene: il nuovo operatore di movimento-costruttore e spostamento-assegnazione sarebbe stato generato automaticamente se era chiaro che l'utente non stava facendo nulla di "speciale" con la classe. Qualunque cosa "speciale" viene definita come ridefinizione del comportamento di spostamento/copia/distruzione.

Per aiutare nel caso in cui le persone avrebbero fatto qualcosa di speciale ma volevano ancora metodi "generati automaticamente", è stato aggiunto anche il rivestimento in zucchero = default.

Sfortunatamente, per motivi di compatibilità con le versioni precedenti, il comitato C++ non ha potuto tornare indietro nel tempo e modificare le regole di generazione automatica per copia; Vorrei che lo avessero deprecato per aprire la strada alla prossima versione dello Standard, ma dubito che lo faranno. è tuttavia deprecato (vedere §12.8/7 per il costruttore di copie, ad esempio, per gentile concessione di @Nevin).

+0

Non l'ho mai sentito chiamare "Regola dei tre grandi" –

+0

@LightnessRacesinOrbit: Aggiunto il link :) –

+0

"Regola di tre" plzkthx –

Problemi correlati