2014-09-09 13 views
5

So che questa domanda potrebbe sembrare molto semplice. Ma non riesco a trovare da nessuna parte un esempio di costruttore di movimento con no puntatori.Move Constructor senza puntatori

Ho una classe che contiene una variabile oggetto vettoriale. Non un puntatore a uno. Quindi la mia domanda: Questo significa che non ho bisogno di un costruttore di mosse? Oppure la mia implementazione è sbagliata e dovrei usare un puntatore a un vettore e quindi usare un costruttore di mosse?

Grazie

+2

Si dovrebbe comunque avere un costruttore di movimento, dal momento che 'std :: vector' può trarre vantaggio dallo spostamento. Lo schema generato dal compilatore (spostamento membro) dovrebbe essere abbastanza buono. –

+0

Credo si chiami * Copy Constructor *, non * Move Constructor *. –

+1

@AlexFarber: il costruttore di copie predefinito è abbastanza buono se non ci sono puntatori membri (come menzionato sopra da T.C.). –

risposta

10

Se la classe contiene oggetti mobili (come ad esempio un vettore), poi basta lasciare che il compilatore genera le operazioni di spostamento implicite. Faranno la cosa giusta, spostando ogni sub-oggetto.

Dovrai scrivere da solo se stai manipolando i puntatori grezzi agli oggetti dinamici o ad altri handle di risorse non gestiti. L'approccio migliore consiste nel disporre di un oggetto correttamente copiabile/mobile (come un contenitore, un puntatore intelligente o un'altra classe RAII) per gestire ciascuno di questi; quindi un oggetto complesso costruito componendo questi avrà implicitamente la semantica di copia/spostamento corretta.

(Come indicato nei commenti: se la classe dichiara il proprio distruttore o le operazioni di copia, allora non otterrà operazioni di spostamento implicite, sarà necessario definirne di proprie, ma se si segue il consiglio di cui sopra, compilandolo da tipi gestiti correttamente che non necessitano di alcuna gestione speciale, non è necessario dichiarare nulla di tutto ciò.)

+0

Quindi lasciare che il compilatore lo generi implicitamente è ancora abbastanza efficiente? O dovrei usare i puntatori? – wjk2a1

+3

@ wjk2a1: L'uso della versione implicita sarà probabilmente più efficiente dell'introduzione di un livello aggiuntivo di riferimento indiretto, e certamente più semplice e meno soggetto a errori. Se hai davvero bisogno di preoccuparti del costo dei singoli aggiornamenti del puntatore, dovrai misurare tu stesso i costi di entrambi gli approcci. –

+0

molto utile, grazie! – wjk2a1

3

Il costruttore di movimento segue linee guida simili a quelle dei costruttori di copie. È necessario quando la classe tiene i membri per puntatore o altri campi di dati fragili (socket, connessioni db, ecc.), In modo che ne generi automaticamente uno che potrebbe rovinare il layout della memoria eliminando due volte lo stesso oggetto. Quindi, se non si dispone di campi di puntatori, non è necessario scrivere costruttore di mosse.

1

Il costruttore di spostamento predefinito e l'allineamento del movimento generato dal compilatore chiameranno il costruttore/assegno di spostamento per ciascun membro della classe.

Se la classe ha solo membri non elaborati, "char * buffer", ad esempio, è necessario scrivere le proprie operazioni di spostamento.

Se la classe ha solo "membri gestiti", "vettore", ad esempio, le operazioni di spostamento predefinite per la classe saranno ok perché delegano l'operazione a ciascun membro.

Se la classe è "gestito membri" mescolato con "membri prime", il vettore e int * ad esempio, le operazioni di movimentazione dovranno fare la mossa manuale delle risorse prime e chiamare operazioni di spostamento per gli oggetti gestiti:

class MyObject { 
public: 
    // ... 


    MyObject(MyObject&& other) : vector1(std::move(other.vector1)) { 
     // We use vector's move constructor^

     // and then move ourself the char* buffer 
     buffer1 = other.buffer1; 
     other.buffer1 = nullptr;   
    } 

    MyObject& operator=(MyObject&& other) { 
     // We use vector's move asignment operator 
     vector1= std::move(other.vector1); 

     // and then move ourself the char* buffer 
     std::swap(buffer1,other.buffer1); 
     return *this; 
    } 

    //... 
private: 
    vector<char> vector1; 
    char * buffer1; 
}; 

std :: move (other.vector1) è necessario perché all'interno di quella funzione other.vector1 è un lvalue. Dobbiamo dire al compilatore che non utilizzeremo il valore vector1 più avanti nel codice funzione in modo che il suo valore possa essere spostato.