2015-04-30 20 views
6

Da un po 'di tempo questo mi ha confuso. E finora non sono riuscito a trovare una risposta soddisfacente. La domanda è semplice. Quando viene chiamato un numero move assignment operator e quando viene chiamato un numero move constructor operator?Differenza tra l'operatore di assegnazione del movimento e il costruttore di movimento?

Gli esempi di codice su cppreference.com producono i seguenti risultati interessanti:

The move assignment operator:

a2 = std::move(a1); // move-assignment from xvalue 

The move constructor:

A a2 = std::move(a1); // move-construct from xvalue 

Così ha fare per con cui viene realizzato? E se sì, che viene eseguito se entrambi sono implementati? E perché c'è la possibilità di creare un sovraccarico dell'operatore di assegnazione del movimento, se è identico comunque.

risposta

11

Un costruttore di movimento viene eseguito solo quando si costruisce un oggetto. Un operatore di assegnazione di movimento viene eseguito su un oggetto costruito in precedenza. È esattamente lo stesso scenario del caso di copia.

Foo foo = std::move(bar); // construction, invokes move constructor 
foo = std::move(other); // assignment, invokes move assignment operator 

Se non li dichiara in modo esplicito, il compilatore li genera per voi (con alcune eccezioni, il cui elenco è troppo lungo per essere pubblicato qui).

Vedere this per una risposta completa a quando le funzioni membro di spostamento sono generate implicitamente.

2

È lo stesso del normale assegnamento di copia e della costruzione della copia.

A a2 = std::move(a1); 
A a2 = a1; 

Coloro chiamare il costruttore spostare/copia, perché a2 non esiste ancora e deve essere costruito. Assegnare non ha senso. Questo modulo è chiamato copia-inizializzazione.

a2 = std::move(a1); 
a2 = a1; 

Quelli nomina di spostamento/copia operatore di assegnazione, perché a2 esiste già, quindi non ha senso costruirlo.

4

Quando un operatore di assegnamento mossa ottenere chiamato

Quando si assegna un rvalue a un oggetto, come si fa nel primo esempio.

e quando viene chiamato un operatore del costruttore di movimento?

Quando si inizializza un oggetto utilizzando un rvalue, come si fa nel secondo esempio. Sebbene non sia un operatore.

Così come è stato implementato?

No, questo determina se può essere utilizzato, non quando potrebbe essere utilizzato.Ad esempio, se non esiste un costruttore di movimento, la costruzione utilizzerà il costruttore di copie se esiste e non riuscirà (con un errore) in caso contrario.

E se sì, che viene eseguito se entrambi sono implementati?

Operatore di assegnazione per assegnazione, costruttore per l'inizializzazione.

E perché esiste la possibilità di creare un sovraccarico dell'operatore di assegnazione del movimento a tutti, se è identico in ogni caso.

Non è identico. Viene invocato su un oggetto che esiste già; il costruttore è invocato per inizializzare un oggetto che in precedenza non esisteva. Spesso devono fare cose diverse. Ad esempio, il compito potrebbe dover cancellare qualcosa, che non esisterà durante l'inizializzazione.

0

movimento costruttore viene chiamato durante:

  • inizializzazione: T a = std :: mossa (b); o T a (std :: move (b)) ;, dove b è di tipo T;
  • argomento di funzione che passa: f (std :: move (a)) ;, dove a è di tipo T e f è void f (T t); operazione di assegnazione

Move è chiamato durante:

  • funzione di ritorno: ritorno a; all'interno di una funzione come T f(), dove a è di tipo T che ha un costruttore di mosse.
  • assegnazione

Il seguente codice di esempio illustra questo:

#include <iostream> 
#include <utility> 
#include <vector> 
#include <string> 
using namespace std; 
class A { 
    public : 
    A() { cout << "constructor called" << endl;} 
    ~A() { cout << "destructor called" << endl;} 
    A(A&&) {cout << "move constructor called"<< endl; return;} 
    A& operator=(A&&) {cout << "move assignment operator called"<< endl; return *this;} 

}; 
A fun() { 
    A a; // 5. constructor called 
    return a; // 6. move assignment operator called 
    // 7. destructor called on this local a 
} 
void foo(A){ 
    return; 
} 
int main() 
{ 
    A a; // 1. constructor called 
    A b; // 2. constructor called 
    A c{std::move(b)}; // 3. move constructor called 
    c = std::move(a); // 4. move assignment operator called 
    a = fun(); 
    foo(std::move(c)); // 8. move constructor called 

} 

uscita:

constructor called 
constructor called 
move constructor called 
move assignment operator called 
constructor called 
move assignment operator called 
destructor called 
move constructor called 
destructor called 
destructor called 
destructor called 
destructor called 
+0

"argomento della funzione di passaggio" è un caso particolare di "inizializzazione" e io sono sicuro cosa intendi per "funzione return". –

+0

'return a;' non è mote-assignment –

+0

@ M.M: per favore aiutami a capire questo come stampare 6 (da dentro fun() dichiarazione) è l'operatore di assegnazione del movimento chiamato. – novieq