web-dev-qa-db-ja.com

STLセットに述語の再評価を強制することは可能ですか?

次のデータ構造とコードを検討してください。

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に述語を再評価させる方法はありますか?

21
merlin2011

番号。

setがその要素へのアクセスを許可するのはconstのみである理由があります。浅い定数のポインターとカスタム述語を使用してそれをこっそり通過し、順序に影響する方法でポインティを変更して不変式を破壊すると、鼻の悪魔の形で価格を支払うことになります。

C++ 17の前に、eraseinsertをもう一度する必要があります。これにより、キーコピーとノードの割り当て解除と割り当てが発生します。その後、ノードをextract、変更、再挿入できます。これは無料です。

34
T.C.