是否可以强制将STL设置为重新评估谓词?

时间:2018-11-20 08:22:37

标签: c++ c++11 stdset

请考虑以下数据结构和代码。

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重新评估谓词,以便顺序再次正确?

1 个答案:

答案 0 :(得分:34)

否。

set仅允许const访问其元素是有原因的。如果您通过使用浅常量指针和自定义谓词来绕过该限制,然后通过以影响订购的方式修改pointee来破坏不变量,则您将以鼻恶魔的形式付出代价。

在C ++ 17之前,您需要再次eraseinsert,这将导致密钥副本以及节点的重新分配和分配。之后,您可以extract节点,对其进行修改并重新插入,这是免费的。