La respuesta a esta pregunta también depende de lo caro que sea crear el tipo de valor que está almacenando en el mapa:
typedef std::map <int, int> MapOfInts;
typedef std::pair <MapOfInts::iterator, bool> IResult;
void foo (MapOfInts & m, int k, int v) {
IResult ir = m.insert (std::make_pair (k, v));
if (ir.second) {
// insertion took place (ie. new entry)
}
else if ( replaceEntry ( ir.first->first ) ) {
ir.second->second = v;
}
}
Para un tipo de valor como un int, lo anterior será más eficiente que una búsqueda seguida de una inserción (en ausencia de optimizaciones del compilador). Como se indicó anteriormente, esto se debe a que la búsqueda en el mapa solo se realiza una vez.
Sin embargo, la llamada para insertar requiere que ya tenga construido el nuevo "valor":
class LargeDataType { /* ... */ };
typedef std::map <int, LargeDataType> MapOfLargeDataType;
typedef std::pair <MapOfLargeDataType::iterator, bool> IResult;
void foo (MapOfLargeDataType & m, int k) {
// This call is more expensive than a find through the map:
LargeDataType const & v = VeryExpensiveCall ( /* ... */ );
IResult ir = m.insert (std::make_pair (k, v));
if (ir.second) {
// insertion took place (ie. new entry)
}
else if ( replaceEntry ( ir.first->first ) ) {
ir.second->second = v;
}
}
Para llamar a 'insertar' estamos pagando por la costosa llamada para construir nuestro tipo de valor, y por lo que dijo en la pregunta, no usará este nuevo valor el 20% del tiempo. En el caso anterior, si cambiar el tipo de valor del mapa no es una opción, entonces es más eficiente realizar primero la 'búsqueda' para verificar si necesitamos construir el elemento.
Alternativamente, el tipo de valor del mapa se puede cambiar para almacenar identificadores de los datos usando su tipo de puntero inteligente favorito. La llamada para insertar usa un puntero nulo (muy barato de construir) y solo si es necesario se construye el nuevo tipo de datos.