Ответ 1
Может ли это быть наихудшей названной функцией в STL?
Немного информации о предыстории: в стандартной библиотеке (или в исходном STL) есть три понятия, контейнеры, итераторы в те контейнеры и алгоритмы, которые применяются к итераторам. Итераторы служат в качестве курсора и аксессора в элементах диапазона, но не имеют ссылки на контейнер (как упоминалось ранее, возможно, даже не был базовым контейнером).
Это разделение имеет приятную особенность, что вы можете применять алгоритмы к диапазонам элементов, которые не принадлежат контейнеру (рассмотрите адаптеры итератора, такие как std::istream_iterator
или std::ostream_iterator
), или что, принадлежащие контейнеру, не учитывают все элементы (std::sort( v.begin(), v.begin()+v.size()/2 )
, чтобы сократить первую половину контейнера).
Отрицательная сторона состоит в том, что, поскольку алгоритм (и итератор) действительно не знает о контейнере, они не могут его изменить, они могут изменять только сохраненные элементы (к чему они могут получить доступ). Алгоритмы мутации, такие как std::remove
или std::remove_if
, работают над этой предпосылкой: они перезаписывают элементы, которые не соответствуют условию, эффективно удаляя их из контейнера, но они не изменяют контейнер, а только содержащиеся значения, которые вызывающий на втором шаге стирания-удаления идиомы:
v.erase( std::remove_if( v.begin(), v.end(), pred ),
v.end() );
Кроме того, для мутирующих алгоритмов (тех, которые выполняют изменения), например, std::remove
, существует не мутирующая версия с именем, добавив copy
к имени: std::remove_copy_if
. Считается, что ни один из алгоритмов XXXcopyYYY
не изменяет входную последовательность (хотя они могут, если вы используете итераторы сглаживания).
В то время как это действительно не является оправданием для именования std::remove_copy_if
, я надеюсь, что это поможет понять, что алгоритм дал свое имя: remove_if
изменит содержимое диапазона и даст диапазон, для которого все элементы, которые соответствуют предикат был удален (возвращаемый диапазон - это тот, который формируется первым аргументом алгоритма возвращенному итератору). std::remove_copy_if
делает то же самое, но вместо того, чтобы модифицировать базовую последовательность, он создает копию последовательности, в которой те элементы, которые соответствуют предикату, были удалены. То есть все алгоритмы * copy * эквивалентны копированию, а затем применяются исходный алгоритм (обратите внимание, что эквивалентность логична, std::remove_copy_if
требует только OutputIterator, что означает, что он не может копировать, а затем пройти скопированный диапазон, применяя std::remove_if
.
Та же линия рассуждений может быть применена к другим алгоритмам мутации: reverse
меняет значения (помните, итераторы не имеют доступа к контейнеру) в диапазоне, reverse_copy
копирует элементы в диапазоне для разделения диапазона в обратный порядок.
Если нет, существует ли алгоритм STL для условного удаления (перемещения?) элементов из контейнера и помещения их в другой контейнер?
В STL нет такого алгоритма, но его можно легко реализовать:
template <typename FIterator, typename OIterator, typename Pred>
FIterator splice_if( FIterator first, FIterator last, OIterator out, Pred p )
{
FIterator result = first;
for ( ; first != last; ++first ) {
if ( p( *first ) ) {
*result++ = *first;
} else {
*out++ = *first;
}
}
return result;
}