удалить не работает правильно - PullRequest
13 голосов
/ 24 января 2011
std::vector<int> v = {1,2,3,4,5};
auto i = std::remove(v.begin(),v.end(),3); 
for(auto j = v.begin(); j!= v.end();++j)
   std::cout << *j;

Фактический объем производства: 12455

Откуда берутся дополнительные 5?

Желаемый вывод: 1245

Как добиться того же?

Я действительно хочу, чтобы размер вектора изменился, ответ, данный Prasoon saurav, выглядит правильным

Ответы [ 4 ]

25 голосов
/ 24 января 2011

remove фактически не удаляет элементы

Удалить удаляет из диапазона [first, last) все элементы, равные value. То есть, remove возвращает итератор new_last такой, что диапазон [first, new_last) не содержит элементов, равных value. 1 Итераторы в диапазоне [new_last, last) все все еще разыменяемы , но элементы, на которые они указывают, являются неопределенными . Удаление является стабильным, это означает, что относительный порядок элементов, которые не равны значению, не изменяется.

std::remove алгоритм работает только с использованием пары прямых итераторов и вообще ничего не знает о базовом контейнере.

Вам необходимо использовать идиому erase-remove для на самом деле удалить элемент, т.е. объединить erase с remove

auto i = std::remove(v.begin(),v.end(),3);
v.erase(i,v.end());
for(auto j = v.begin(); j!= v.end();++j)
   std::cout << *j;
5 голосов
/ 24 января 2011

Прочитайте документацию для std::remove еще раз.

Функция не удаляет элементы из контейнера (фактически, она даже не знает , что контейнер задействован, поскольку видит только итераторы), она просто перемещает значения вупорядочить и вернуть новый итератор i так, чтобы весь интервал [ begin .. i [ содержал все не удаленные элементы в исходном порядке.Элементы, оставшиеся в [ i .. end [, не определены, и вы обязаны исключить этот интервал из контейнера (если он вам нужен):

auto i = std::remove(...);
v.erase(i,v.end());

Причина, по которой у вас есть дополнительный 5, заключается в том, чтотипичный алгоритм удаления копирует значения в отверстия, оставленные удаленными значениями, и поскольку значения после итератора i никогда не перезаписываются, они остаются такими же, как в исходной последовательности.Такое поведение, однако, ненадежно - просто удалите значения после i, не читая их.

2 голосов
/ 24 января 2011

remove возвращает новый конец.Итак, исправление вашего кода таково:

 std::vector<int> v = {1,2,3,4,5};
 auto newEnd = std::remove(v.begin(),v.end(),3);//return value stored in newEnd
 for(auto j = v.begin(); j!= newEnd ;++j) //note j!=newEnd
     std::cout << *j;

Вывод:

1245

Проверьте сами: http://www.ideone.com/3AMD9

0 голосов
/ 24 января 2011

Это швы, что вы печатаете n + 1 позицию вектора в операторе for().Должно быть:

for(auto j = v.begin(); j!= v.end();j++)
   std::cout << *j;

j++ нет ++j

...