代码之家  ›  专栏  ›  技术社区  ›  merlin2011

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

  •  21
  • merlin2011  · 技术社区  · 6 年前

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

    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 回复  |  直到 6 年前
        1
  •  34
  •   anatolyg    6 年前

    不。

    这是有原因的 set 只允许 const 访问其元素。如果您通过使用浅常量指针和自定义谓词,然后通过以影响排序的方式修改指针来破坏不变量,那么您将以鼻部恶魔的形式付出代价。

    在C++ 17之前,您需要 erase insert 同样,这会导致一个键复制加上节点释放和分配。之后,你可以 extract 节点,修改它,然后重新插入它,这是自由的。