是否可以强制 STL 集重新评估谓词?
Is it possible to force STL set to reevaluate predicate?
考虑以下数据结构和代码。
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
节点,修改它,然后重新插入它,这是免费的。
考虑以下数据结构和代码。
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
节点,修改它,然后重新插入它,这是免费的。