La réponse à cette question dépend également du coût de création du type de valeur que vous stockez dans la carte:
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;
}
}
Pour un type valeur tel qu'un int, ce qui précède sera plus efficace qu'une recherche suivie d'une insertion (en l'absence d'optimisations du compilateur). Comme indiqué ci-dessus, cela est dû au fait que la recherche sur la carte n'a lieu qu'une seule fois.
Cependant, l'appel à insérer nécessite que vous ayez déjà construit la nouvelle "valeur":
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;
}
}
Afin d'appeler «insert», nous payons l'appel coûteux pour construire notre type de valeur - et d'après ce que vous avez dit dans la question, vous n'utiliserez pas cette nouvelle valeur 20% du temps. Dans le cas ci-dessus, si la modification du type de valeur de la carte n'est pas une option, il est alors plus efficace d'effectuer d'abord la «recherche» pour vérifier si nous devons construire l'élément.
Vous pouvez également modifier le type de valeur de la carte pour stocker les poignées des données à l'aide de votre type de pointeur intelligent préféré. L'appel à insérer utilise un pointeur nul (très bon marché à construire) et seulement si nécessaire le nouveau type de données est construit.