standard entre diferencias c++ c++17

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, como std::unique_ptr .
  • try_emplace() trata la clave y los argumentos al mapped_type separado, lo que lo hace algo más intuitivo que los mutadores genéricos que se expresan en términos de value_type (que es std::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); }