Можно ли заставить 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 переоценить предикаты, чтобы порядок снова был правильным?

1 ответ

Решение

Нет.

Есть причина, почему set только позволяет const доступ к его элементам. Если вы пробьетесь мимо этого с помощью указателей с мелкой константой и пользовательских предикатов, а затем уничтожите инвариант, изменив указатель таким образом, что это повлияет на порядок, вы заплатите цену в виде носовых демонов.

До C++17 вам нужно erase а также insert опять же, что влечет за собой копирование ключа плюс освобождение и распределение узла. После вы можете extract узел, измените его и вставьте заново, что бесплатно.

Другие вопросы по тегам