standard - diferencias entre c++ y c++ 11
¿Hay alguna razón para usar std:: map:: emplace() en lugar de try_emplace() en C++ 1z? (3)
Siempre preferiría try_emplace sobre emplace. Una diferencia fundamental es que try_emplace no construirá el objeto asociado con la clave, si la clave ya existe. Esto aumentará el rendimiento en caso de que sea costoso crear objetos de ese tipo.
Por ejemplo, el siguiente código (Ejemplo de https://github.com/PacktPublishing/Cpp17-STL-Cookbook/blob/master/Chapter02/efficient_insert_or_reassign_to_map.cpp )
#include <iostream>
#include <functional>
#include <list>
#include <map>
using namespace std;
struct billionaire {
string name;
double dollars;
string country;
};
int main()
{
list<billionaire> billionaires {
{"Bill Gates", 86.0, "USA"},
{"Warren Buffet", 75.6, "USA"},
{"Jeff Bezos", 72.8, "USA"},
{"Amancio Ortega", 71.3, "Spain"},
{"Mark Zuckerberg", 56.0, "USA"},
{"Carlos Slim", 54.5, "Mexico"},
// ...
{"Bernard Arnault", 41.5, "France"},
// ...
{"Liliane Bettencourt", 39.5, "France"},
// ...
{"Wang Jianlin", 31.3, "China"},
{"Li Ka-shing", 31.2, "Hong Kong"}
// ...
};
map<string, pair<const billionaire, size_t>> m;
for (const auto &b : billionaires) {
auto [iterator, success] = m.try_emplace(b.country, b, 1);
if (!success) {
iterator->second.second += 1;
}
}
for (const auto & [key, value] : m) {
const auto &[b, count] = value;
cout << b.country << " : " << count << " billionaires. Richest is "
<< b.name << " with " << b.dollars << " B$/n";
}
}
Para el código anterior
m.try_emplace(b.country, b, 1);
Si no hay una inserción exitosa, los pares no se construirán, lo que aumenta el rendimiento.
En C ++ 17, std::map
y std::unordered_map
obtuvieron una nueva plantilla de función miembro: try_emplace()
. Esta nueva adición, propuesta en n4279 , se comporta de manera similar a emplace()
, pero tiene las siguientes ventajas:
-
try_emplace()
no se mueve de los argumentos de rvalue si la inserción no ocurre. Esto es útil cuando se manipulan mapas cuyos valores son tipos de solo movimiento, comostd::unique_ptr
. -
try_emplace()
trata la clave y los argumentos almapped_type
separado, lo que lo hace algo más intuitivo que los mutadores genéricos que se expresan en términos devalue_type
(que esstd::pair
).
Teniendo en cuenta las ventajas anteriores, ¿utilizaría alguna vez emplace()
de C ++ 11 en lugar de try_emplace()
de C ++ 1z al escribir código solo de C ++ 1z?
try_emplace
puede, de hecho, reemplazar la mayoría de los usos de emplace
, pero si tiene un caso de uso inusual de un map
con un tipo de clave no copiable e inamovible, try_emplace
no funcionará porque copia o mueve la clave. En ese caso, debe usar emplace
con el constructor de construcción por partes de std::pair
para evitar copias y movimientos.
Incluso si su tipo de clave es copiable y / o movible, la construcción por partes es la única forma de evitar copiar o mover la construcción de la clave, por lo que puede haber casos en los que lo prefiera sobre try_emplace
.
try_emplace
tampoco admite búsquedas heterogéneas, no puede porque toma la clave.
Supongamos que tenemos un std::map<std::string, int, std::less<>> counts;
y un std::string_view
sv
. Quiero hacer el equivalente de ++counts[std::string(sv)];
, pero no quiero crear una std::string
temporal std::string
, que es un desperdicio, especialmente si la cadena ya está presente en el mapa. try_emplace
no puede ayudarte allí. En su lugar, harías algo como
if(auto lb = counts.lower_bound(sv); lb != counts.end() && lb->first == sv) {
++lb->second;
}
else {
counts.emplace_hint(lb, sv, 1);
}