Sebbene la risposta esistente fornisca una soluzione alternativa utilizzando std::move
per la compilazione del programma, è necessario dire che l'utilizzo di emplace_back
sembra essere basato su un malinteso.
Il modo in cui lo descrivete ("Stavo cercando di [...] spostare il contenuto da un vettore ad un altro utilizzando emplace_back()
") e il modo in cui lo si utilizza suggeriscono che si pensa di emplace_back
come metodo a sposta elementi nel vettore e di push_back
come metodo per copia elementi in un vettore.Il codice utilizzato per riempire la prima istanza del vettore sembra suggerire anche questo:
std::vector<obj> v;
for(int i = 0; i < 1000; ++i)
{
v.emplace_back(obj("Jon"));
}
Ma questo non è ciò che la differenza tra emplace_back
e push_back
è circa.
primo luogo, anche push_back
si spostare (non copiare) gli elementi nel vettore se solo viene dato un rvalue, e se il tipo di elemento ha un operatore di assegnazione mossa.
In secondo luogo, il vero caso d'uso di emplace_back
è quello di costruire elementi in luogo, vale a dire lo si usa quando si vuole mettere gli oggetti in un vettore che non esiste ancora. Gli argomenti di emplace_back
sono gli argomenti per il costruttore dell'oggetto. Così il ciclo di cui sopra dovrebbe davvero guardare in questo modo:
std::vector<obj> v;
for(int i = 0; i < 1000; ++i)
{
v.emplace_back("Jon"); // <-- just pass the string "Jon" , not obj("Jon")
}
Il motivo per cui il codice esistente funziona è che obj("Jon")
è anche un argomento valido per il costruttore (in particolare, al costruttore mossa). Ma l'idea principale di emplace_back
è che non è necessario creare l'oggetto e quindi spostarlo. Non si beneficia di tale idea quando si passa obj("Jon")
anziché "Jon"
.
D'altra parte, nel secondo ciclo si tratta di oggetti creati in precedenza. Non ha senso usare emplace_back
per spostare oggetti già esistenti. E ancora, emplace_back
applicato a un oggetto esistente non significa che l'oggetto è stato spostato. Significa solo che è creato sul posto, usando il normale costruttore di copie (se esiste). Se si desidera spostarlo, è sufficiente utilizzare push_back
, applicata al risultato di std::move
:
std::vector<obj> p;
for(int i = 0; i < 1000; ++i)
{
p.push_back(std::move(v[i])); // <-- Use push_back to move existing elements
}
Ulteriori note
1) È possibile semplificare il ciclo sopra utilizzando C++ 11 gamma-based per:
std::vector<obj> p;
for (auto &&obj : v)
p.push_back(std::move(obj));
2) Indipendentemente dal fatto che si utilizza un normale ciclo for o gamma-based per, si muovono gli elementi uno per uno, il che significa che la fonte vettore v
rimarrà come un vettore di 1000 oggetti vuoti. Se si vuole realmente cancellare il vettore nel processo (ma ancora utilizzare la semantica si muovono per trasportare gli elementi per il nuovo vettore), è possibile utilizzare il costruttore mossa del vettore stesso:
std::vector<obj> p(std::move(v));
Questo riduce il secondo ciclo a una sola riga, e si assicura che il vettore sorgente sia cancellato.
Il messaggio di errore indica che 'obj' ha bisogno di un costruttore di copie. – Mat
@mat perché deve essere costruito? non dovrebbe usare il costruttore di mosse + l'operatore di assegnazione del movimento? – user1849534
Controlla la definizione di [emplace_back] (http://en.cppreference.com/w/cpp/container/vector/emplace_back), hai bisogno di un costruttore che prenda ciò che stai passando 'emplace_back'. Stai passando un valore-l e non hai un costruttore che corrisponda. – Mat