cpp-ru / ideas

Идеи по улучшению языка C++ для обсуждения
https://cpp-ru.github.io/proposals
Creative Commons Zero v1.0 Universal
89 stars 0 forks source link

Аналог метода extract для std::set/std::map, когда исходный контейнер больше не потребуется #582

Open prigluchenie opened 7 months ago

prigluchenie commented 7 months ago

Проблема Для переноса узла std::set в другой экземпляр контейнера (возможно, с попутной модификацией ключа) есть метод extract, который позволяет переиспользовать аллокацию. Однако частно это требуется сделать для всех элементов контейнера, и исходный контейнер больше не нужен.

Пример, как можно реализовать условную задачу сейчас

std::set<std::string> input{"a", "b", "c"}; 
std::set<std::string> output_good, output_bad;

while(!input.empty()) {
    auto node_handler = input.extract(input.begin());
    if (is_good(node_handler.value()) {
        node_handler.value() += '!';
        output_good.insert(std::move(node_handler));
    } else {
        output_bad.insert(std::move(node_handler));
    }
}

Недостаток этого решения в том, что между итерациями цикла приходится восстанавливать инварианты черно-красного дерева, что избыточно, т.к. объект больше не требуется (в итоге заведомо остается пустой).

Предлагается добавить метод extract_each (условно), который бы позволял максимально эффективно разобрать дерево на отдельные ноды целиком.

Например, код решения исходной задачи с таким методом мог бы выглядеть как-то так

std::move(input).extract_each([&output_good, &output_bad](auto node_handler) {
    if (is_good(node_handler.value()) {
        node_handler.value() += '!';
        output_good.insert(std::move(node_handler));
    } else {
        output_bad.insert(std::move(node_handler));
    }
});

Можно подумать и над вариантом метода extract с дополнительными параметрами диапазона итераторов from, to, и с аналогичным функтором для передачи владения узлами.

GitSparTV commented 7 months ago

А может merge с перегрузкой для rvalue?

prigluchenie commented 7 months ago

А может merge с перегрузкой для rvalue?

Это решает лишь частный случай, когда