unordered_set - unordered_map c++ example
¿Cuál es la diferencia entre unordered_map:: emplace y unordered_map:: insert en C++? (1)
unordered_map::insert
copia o mueve un par clave-valor al contenedor. Está sobrecargado para aceptar referencia a const o una referencia rvalue :
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
permite evitar copias o movimientos innecesarios al construir el elemento en su lugar. Utiliza un reenvío perfecto y una plantilla variadic para reference :
template<class... Args>
std::pair<iterator,bool> emplace(Args&&... args);
Pero hay una gran cantidad de superposición entre las dos funciones. emplace
se puede usar para reenviar al constructor de copia / movimiento del par clave-valor que permite que se use como lo haría insert
. Esto significa que el uso de emplace
no garantiza que evitará copias o movimientos. Además, la versión del insert
que toma una referencia-r es en realidad una plantilla y acepta cualquier tipo P
modo que el par clave-valor es construible a partir de P
En principio, las funciones de emplazamiento a veces deberían ser más eficientes que sus contrapartes de inserción, y nunca deberían ser menos eficientes.
( Edit: Howard Hinnant realizó algunos experimentos que mostraron que algunas veces insert
es más rápido que emplace
)
Si definitivamente desea copiar / mover en el contenedor, puede ser conveniente utilizar insert
porque es más probable que obtenga un error de compilación si pasa argumentos incorrectos. Debe tener más cuidado al pasar los argumentos correctos a las funciones de emplazamiento.
La mayoría de las implementaciones de unordered_map::emplace
harán que la memoria se asigne dinámicamente para el nuevo par, incluso si el mapa ya contiene un elemento con esa clave y el emplace
fallará. Esto significa que si existe una buena probabilidad de que falle un emplace
, es posible que obtenga un mejor rendimiento al usar la función de inserción para evitar asignaciones de memoria dinámica innecesarias.
Pequeño ejemplo:
#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: a petición. También es posible usar unordered_map::emplace
con una clave o valor que toma más de un parámetro de constructor. Usando el constructor std::pair
partes , aún puede evitar copias o movimientos innecesarios.
#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
}
¿Cuál es la diferencia entre std::unordered_map::emplace
y std::unordered_map::insert
en C ++?