Tenez compte des structures de données et du code suivants.
struct Sentence {
std::string words;
int frequency;
Sentence(std::string words, int frequency) : words(words), frequency(frequency) {}
};
struct SentencePCompare {
bool operator() (const Sentence* lhs, const Sentence* rhs) const {
if (lhs->frequency != rhs->frequency) {
return lhs->frequency > rhs->frequency;
}
return lhs->words.compare(rhs->words) < 0;
}
};
std::set<Sentence*, SentencePCompare> sentencesByFrequency;
int main(){
Sentence* foo = new Sentence("foo", 1);
Sentence* bar = new Sentence("bar", 2);
sentencesByFrequency.insert(foo);
sentencesByFrequency.insert(bar);
for (Sentence* sp : sentencesByFrequency) {
std::cout << sp->words << std::endl;
}
foo->frequency = 5;
for (Sentence* sp : sentencesByFrequency) {
std::cout << sp->words << std::endl;
}
}
La sortie du code ci-dessus est la suivante.
bar
foo
bar
foo
Comme nous pouvons nous y attendre, lorsqu'un objet pointé par le pointeur de l'ensemble est mis à jour, l'ensemble ne réévalue pas automatiquement le prédicat, même si le prédicat ordonne les pointeurs en fonction des objets vers lesquels ils pointent.
Existe-t-il un moyen de forcer le std::set
pour réévaluer les prédicats, afin que l'ordre soit à nouveau correct?
Non.
Il y a une raison pour laquelle set
n'autorise que const
à accéder à ses éléments. Si vous vous faufilez en utilisant des pointeurs constants peu profonds et des prédicats personnalisés, puis détruisez l'invariant en modifiant la pointe d'une manière qui affecte l'ordre, vous en paierez le prix sous la forme de démons nasaux.
Avant C++ 17, vous devez à nouveau erase
et insert
, ce qui entraîne une copie de clé plus la désallocation et l'allocation des nœuds. Après, vous pouvez extract
le nœud, le modifier et le réinsérer, ce qui est gratuit.