2016-02-15 20 views
11

C'è qualche vantaggio nell'utilizzo di std::vector::emplace_back e std::move insieme? o è ridondante dal momento che lo std::vector::emplace_back eseguirà una costruzione interna?std :: vector :: emplace_back e std :: move

Casi di chiarimento:

std::vector<std::string> bar; 

Primo:

bar.emplace_back(std::move(std::string("some_string"))); 

In secondo luogo:

std::string str("some_string"); 
bar.emplace_back(std::move(str)); 

Terzo:

bar.emplace_back(std::move("some_string")); 
+1

La terza mossa, perlomeno, è inutile. Quella stringa letterale è const, quindi non può essere spostata. –

risposta

13

Nella seconda versione, c'è un vantaggio. La chiamata al numero emplace_back chiamerà il costruttore di spostamenti di std::string quando viene utilizzato std::move, che potrebbe salvare su una copia (a condizione che tale stringa non sia archiviata in un buffer SSO). Si noti che questo è essenzialmente lo stesso di push_back in questo caso.

std::move nella prima versione non è necessario poiché la stringa è già un valore.

std::move nella terza versione è irrilevante, poiché non è possibile spostare una stringa letterale.

Il metodo più semplice e più efficace è questo:

bar.emplace_back("some_string"); 

che non richiede inutili std::string costruzioni come il letterale è perfetto-inoltrato al costruttore.

+0

Potrebbe chiarire "lo stesso di' push_back' in questo caso "? In tal caso esattamente? Può 'emplace_back' essere sempre sostituito con 'push_back' se il suo argomento è' move'd? –

1

C'è un motivo per farlo nel secondo caso. Considerate questo codice:

int main() 
{ 
    std::vector<std::string> bar; 
    std::string str("some_string"); 
    bar.emplace_back(std::move(str)); 
    // bar.emplace_back(str); 
    std::cout << str << std::endl; 
} 

Se si modifica il commento alla riga precedente, si può vedere che si finisce con due copie di "some_string" (uno in bar e uno in str). Quindi cambia qualcosa.

In caso contrario, il primo si muove temporaneamente e il terzo sta spostando un valore letterale a stringa costante. Non fa nulla.

2

L'idea di emplace_back è di eliminare le operazioni di copia e spostamento. Hai solo bisogno di passare i parametri di input di std::string in emplace_back. Un oggetto std::string verrà costruito all'interno del metodo emplace_back.

bar.emplace_back("some_string"); 

Se si dispone già di una stringa, senso utilizzare std::move. Un oggetto std::string verrà costruito all'interno di emplace_back spostando i dati da str.

std::string str("some_string"); 
bar.emplace_back(std::move(str)); 
4

emplace_back chiamate a somehthing come

new (data+size) T(std::forward<Args>(args)...); 

se args sono di base - non - rvalue-referenziato std::string, l'espressione verrà compilato per

new (data+size) std::string(str); //str is lvalue - calls std::string::string(const string& rhs) 

significa che il costruttore di copia avrà posto. ma, se si utilizza std::move sul str, il codice verrà compilato per

new (data+size) std::string(str); //str is r-value reference, calls std::string::string(string&& rhs) 

quindi spostare la semantica si svolge. questo è un enorme guadagno in termini di prestazioni.
notate, che str è lvalue, ha un nome, quindi per creare un valore-riferimento da esso, è necessario utilizzare std::move.

nell'esempio

vec.emplace_back("some literal"); 

il codice verrà compilato per

new (data+size) std::string("literal"); //calls std::string::string(const char*); 

quindi nessuna provvisori.

il terzo esempio non ha senso. non puoi spostare letterali.