次のデータ構造とコードを検討してください。
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;
}
}
上記のコードの出力は次のとおりです。
bar
foo
bar
foo
予想されるように、セット内のポインターが指すオブジェクトが更新されると、たとえ述語が指しているオブジェクトに基づいてポインターを順序付けしても、セットは述語を自動的に再評価しません。
順序が再び正しいように、std::set
に述語を再評価させる方法はありますか?
番号。
set
がその要素へのアクセスを許可するのはconst
のみである理由があります。浅い定数のポインターとカスタム述語を使用してそれをこっそり通過し、順序に影響する方法でポインティを変更して不変式を破壊すると、鼻の悪魔の形で価格を支払うことになります。
C++ 17の前に、erase
とinsert
をもう一度する必要があります。これにより、キーコピーとノードの割り当て解除と割り当てが発生します。その後、ノードをextract
、変更、再挿入できます。これは無料です。