是否有可能强制STL设置重新评估谓词?

mer*_*011 21 c++ stdset c++11

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

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

以上代码的输出如下.

bar
foo
bar
foo
Run Code Online (Sandbox Code Playgroud)

正如我们所预料的那样,当更新集合中指针所指向的对象时,即使谓词根据指向的对象对指针进行排序,该集合也不会自动重新评估谓词.

有没有办法强制std::set重新评估谓词,以便订单再次正确?

T.C*_*.C. 34

没有.

有一个原因,set只允许const访问其元素.如果你通过使用浅const指针和自定义谓词偷偷过去,然后通过以影响排序的方式修改指针来破坏不变量,你将以鼻子恶魔的形式付出代价.

C++ 17之前,你需要eraseinsert再次,这将产生密钥副本加点释放和分配.之后,您可以extract对节点进行修改,然后将其重新插入,这是免费的.

  • @anatolyg你真的[`extract`](https://en.cppreference.com/w/cpp/container/set/extract)它. (4认同)
  • 它不是真正免费的,它避免了重新分配节点的成本,但仍然需要重新计算新节点所在的位置,这需要大约对数时间. (4认同)