2014-10-19 11 views
15

Qual è la differenza tra unordered_map :: emplace e unordered_map :: insert in C++?Qual è la differenza tra unordered_map :: emplace e unordered_map :: insert in C++?

+3

Tratto da un [riferimento] (http://en.cppreference.com/w/cpp/container/unordered_map/emplace): * uso attento della colloco permette al nuovo elemento da costruire evitando inutili copia o spostare le operazioni. Il costruttore del nuovo elemento (cioè 'std :: pair ') viene chiamato con esattamente gli stessi argomenti forniti per emplace, inoltrato tramite 'std :: forward (args) ...'. * – chris

+0

emplace crea un nuovo oggetto mentre insert prende un oggetto esistente.I parametri sono diversi poiché emplace accetta gli argomenti del costruttore. Se non si dispone di un'istanza già esistente da inserire, utilizzare emplace. –

risposta

25

unordered_map::insert copia o sposta una coppia chiave-valore nel contenitore. It is overloaded to accept reference-to-const or an rvalue reference:

std::pair<iterator,bool> insert(const std::pair<const Key, T>& value); 

template<class P> 
std::pair<iterator,bool> insert(P&& value); 

unordered_map::emplace consente di evitare copie non necessarie o si muove costruendo l'elemento al suo posto. Si utilizza l'inoltro perfetto e un modello variadic a forward arguments to the constructor of the key-value pair:

template<class... Args> 
std::pair<iterator,bool> emplace(Args&&... args); 

Ma c'è una grande quantità di sovrapposizione tra le due funzioni. emplace può essere utilizzato per inoltrare al costruttore copia/sposta della coppia chiave-valore che consente di utilizzarlo nello stesso modo di insert. Ciò significa che l'uso di emplace non garantisce l'assenza di copie o spostamenti. Anche la versione di insert che accetta un riferimento di rvalue è in realtà un modello e accetta qualsiasi tipo P in modo tale che la coppia chiave-valore sia costruibile da P.

Scott Meyers says:

In linea di principio, funzioni emplacement dovrebbe essere a volte più efficiente delle loro controparti di inserimento, e non devono mai essere inferiore efficiente.

(Edit: Howard Hinnant corse some experiments che ha mostrato a volte insert è più veloce di emplace)

Se sicuramente non desidera copiare/spostare nel contenitore potrebbe essere saggio usare insert perché sei più probabilità di ottenere un errore di compilazione se si passano argomenti non corretti. Devi essere più attento a passare gli argomenti corretti alle funzioni di posizionamento.

La maggior parte delle implementazioni di unordered_map::emplace causerà l'allocazione dinamica della memoria per la nuova coppia anche se la mappa contiene già un elemento con quella chiave e lo emplace non riuscirà. Ciò significa che se c'è una buona probabilità che un emplace fallisca, potresti ottenere prestazioni migliori usando insert per evitare allocazioni di memoria dinamica non necessarie.

piccolo esempio:

#include <unordered_map> 
#include <iostream> 

int main() { 
    auto employee1 = std::pair<int, std::string>{1, "John Smith"}; 

    auto employees = std::unordered_map<int, std::string>{}; 

    employees.insert(employee1); // copy insertion 
    employees.insert(std::make_pair(2, "Mary Jones")); // move insertion 
    employees.emplace(3, "James Brown"); // construct in-place 

    for (const auto& employee : employees) 
    std::cout << employee.first << ": " << employee.second << "\n"; 
} 

Edit2: Su richiesta. È anche possibile utilizzare unordered_map::emplace con una chiave o un valore che richiede più di un parametro del costruttore. Usando lo std::pairpiecewise constructor puoi comunque evitare copie o spostamenti non necessari.

#include <unordered_map> 
#include <iostream> 

struct Employee { 
    std::string firstname; 
    std::string lastname; 
    Employee(const std::string& firstname, const std::string& lastname) 
    : firstname(firstname), lastname(lastname){}  
}; 

int main() { 
    auto employees = std::unordered_map<int, Employee>{}; 
    auto employee1 = std::pair<int, Employee>{1, Employee{"John", "Smith"}}; 

    employees.insert(employee1); // copy insertion 
    employees.insert(std::make_pair(2, Employee{"Mary", "Jones"})); // move insertion 
    employees.emplace(3, Employee("Sam", "Thomas")); // emplace with pre-constructed Employee 
    employees.emplace(std::piecewise_construct, 
        std::forward_as_tuple(4), 
        std::forward_as_tuple("James", "Brown")); // construct in-place 
} 
+0

* "Le funzioni di posizionamento sono spesso più efficienti delle controparti di inserimento e non sono mai meno efficienti." * Howard Hinnant ha misurato qualcosa di diverso: http://htmlpreview.github.io/?https://github.com/HowardHinnant /papers/blob/master/insert_vs_emplace.html Vedi anche: https://groups.google.com/a/isocpp.org/forum/?fromgroups#!searchin/std-discussion/emplace/std-discussion/YQ4BGAvxIhw/jTfn1RIm9IkJ – dyp

+0

@dyp vedere anche non funziona per me su mobile firefox – Yakk

+0

@Yakk Ah, mi dispiace. Spero che funzioni: https://groups.google.com/a/isocpp.org/d/topic/std-discussion/YQ4BGAvxIhw/discussion 'emplace' per i contenitori associativi in ​​genere crea l'elemento (non solo la chiave) dagli argomenti anche se non è inserito. Quindi se hai già un elemento (fuori dal contenitore associativo) e vuoi copiarlo, 'inserire' potrebbe essere più efficiente. – dyp

Problemi correlati