STL удалить не работает, как ожидалось?
4822 просмотра
3 ответа
int main()
{
const int SIZE = 10;
int a[SIZE] = {10, 2, 35, 5, 10, 26, 67, 2, 5, 10};
std::ostream_iterator< int > output(cout, " ");
std::vector< int > v(a, a + SIZE);
std::vector< int >::iterator newLastElement;
cout << "contents of the vector: ";
std::copy(v.begin(), v.end(), output);
newLastElement = std::remove(v.begin(), v.end(), 10);
cout << "\ncontents of the vector after remove: ";
//std::copy(v.begin(), newLastElement, output);
//this gives the correct result : 2 35 5 26 67 2 5
std::copy(v.begin(), v.end(), output);
//this gives a 10 which was supposed to be removed : 2 35 5 26 67 2 5 2 5 10
cout << endl;
return 0;
}
В массиве три 10 а.
почему массив v содержит 10 после удаления всех 10 с помощью функции remove.
вы можете увидеть скомпилированный вывод также здесь
Автор: munish Источник Размещён: 12.11.2019 09:38Ответы (3)
28 плюса
На самом деле std::remove
не удаляет элемент из контейнера. Цитируется здесь
Удалить удаляет из диапазона
[first, last)
все элементы, которые равныvalue
. То есть, remove возвращает итераторnew_last
, так что диапазон не[first, new_last)
содержит элементов, равныхvalue
. Все итераторы в диапазоне[new_last, last)
все еще разыменовываются , но элементы, на которые они указывают, не определены . Удаление является стабильным, это означает, что относительный порядок элементов, которые не равны значению, не изменяется.
То есть std::remove
работает только с парой итераторов и ничего не знает о контейнере, который фактически содержит элементы. На самом деле, невозможно std::remove
узнать нижележащий контейнер, потому что он не может пройти путь от пары итераторов, чтобы узнать о контейнере, к которому принадлежат итераторы. Так std::remove
что на самом деле не удаляет предметы, просто потому что не может . Единственный способ фактически удалить элемент из контейнера - это вызвать функцию-член этого контейнера.
Поэтому, если вы хотите удалить элементы, используйте Erase-Remove Idiom :
v.erase(std::remove(v.begin(), v.end(), 10), v.end());
Стирающий удалить идиомы настолько общее и полезным в том , что std::list
добавило еще одну функции - члена , называемую , list::remove
который производит тот же эффект, что и erase-remove
идиома.
std::list<int> l;
//...
l.remove(10); //it "actually" removes all elements with value 10!
Это означает, что вам не нужно использовать erase-remove
идиому, когда вы работаете с std::list
. Вы можете напрямую вызвать его функцию-член list::remove
.
11 плюса
Причина в том, что алгоритмы STL не изменяют размер последовательности. remove
вместо того, чтобы действительно стирать элементы, перемещает их и возвращает итератор в «новый» конец. Затем этот итератор может быть передан в erase
функцию-член вашего контейнера для фактического выполнения удаления:
v.erase(std::remove(v.begin(), v.end(), 10), v.end());
Между прочим, это известно как идиома удаления-удаления.
РЕДАКТИРОВАТЬ: я был не прав. Смотрите комментарии и ответ Наваза.
Автор: Etienne de Martel Размещён: 23.06.2011 03:491 плюс
Поскольку на std::remove
самом деле контейнер не уменьшается, он просто перемещает все элементы вниз, чтобы заполнить место, используемое «удаленным» элементом. Например, если у вас есть последовательность 1 2 3 4 5
и вы используете ее std::remove
для удаления значения 2
, ваша последовательность будет выглядеть следующим образом 1 3 4 5 5
. Если вы затем удалите значение 4
, вы получите 1 3 5 5 5
. Ни в коем случае последовательность не может быть короче.
Вопросы из категории :
- c++ What are the barriers to understanding pointers and what can be done to overcome them?
- c++ Какой самый простой способ для анализа файла INI в C ++?
- c++ Когда вы должны использовать «друг» в C ++?
- c++ Как вы очищаете переменную stringstream?
- c++ В C ++ конструктор и деструктор могут быть встроенными функциями?
- c++ Что такое виртуальный базовый класс в C ++?
- c++ В чем разница между #include <filename> и #include "filename"?
- c++ Какой самый лучший бесплатный детектор утечки памяти для программы на C / C ++ и ее подключаемых библиотек DLL?
- c++ Как преобразовать std :: string в LPCWSTR в C ++ (Unicode)
- c++ Regular cast vs. static_cast vs. dynamic_cast
- stl Зачем использовать итераторы вместо индексов массива?
- stl Инициализация статического std :: map <int, int> в C ++
- stl К STL или! STL, вот в чем вопрос
- stl Строка c_str () против данных ()
- stl Объединение двух стандартных: векторов
- stl Является ли list :: size () действительно O (n)?
- stl Как отсортировать std :: vector по значениям другого std :: vector?
- stl Проверка контейнеров STL в Xcode
- stl Как вы вставляете с reverse_iterator
- stl Форвард объявить контейнер STL?