cpp-ru/ideas

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

prigluchenie opened this issue · 2 comments

Проблема
Для переноса узла 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, и с аналогичным функтором для передачи владения узлами.

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

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

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

  • нужно перенести узлы в единственную мапу, а не раскладывать по разным
  • не позволяет отбросить отдельные узлы по условию
  • не позволяет увидеть узел с правом inplace-модификации ключа