2013-11-15 4 views
4

Предположим, вы хотите удалить один элемент из вектора по значению. В чем разница между remove -Стиранием:В чем разница между remove-erase и find-erase

vector<int> v; 
// add some values 
vector<int>::iterator it = remove(v.begin(), v.end(), 5); 
v.erase(it); 

И найти стертого

vector<int> v; 
// add some values 
vector<int>::iterator it = find(v.begin(), v.end(), 5); 
if(it != v.end()) 
{ 
    v.erase(it); 
} 
+0

[Я сделал здесь два комментария, но они оба были неправы, пожалуйста, игнорируйте :-)] –

+0

Здесь лучше ответить: https://stackoverflow.com/questions/24011627/erasing-using-iterator-from- find-or-remove – giuseppe

ответ

13

Неверный код удаления. Удалить стирание идиомы выглядит следующим образом:

vector<int>::iterator it = remove(v.begin(), v.end(), 5); 
v.erase(it, v.end()); 

В этом случае он имеет эффект стирания всех значений, равных 5, но это сводит к минимуму количество копирования, необходимое для достижения этой цели.

Ваш код удаления удаляет только первое значение, равное 5, поэтому он делает то, что вы хотите.

Код удаления удаляет все значения, не равные 5, перед вектором (это то, что делает std::remove), удаляет один из оставшихся элементов вектора и оставляет после себя оставшиеся элементы с неопределенными значениями (что также является то, что делает remove). Он имеет неопределенное поведение, если вектор не содержит 5 для начала, потому что remove вернет v.end() в этом случае.

Итак, если вы хотите стереть только один элемент из нескольких равных 5, то std::remove вам не подходит, потому что он не сохраняет 5 других.Если вы хотите, чтобы переместить не-5 значений в начале и 5 значений до конца, перед удалением первого из 5s, то вы могли бы на самом деле сделать это с std::partition просто не с std::remove:

auto it = partition(v.begin(), v.end(), [](int i) { return i != 5; }); 
if (it != v.end()) v.erase(it); 

Хотя, так как один-так же хорошо, как и другие, вы получите тот же результат, удалив последние из 5s, а не первый, и это более эффективно, когда есть более чем один из них:

auto it = partition(v.begin(), v.end(), [](int i) { return i != 5; }); 
if (it != v.end()) v.pop_back(); 

Если вы можете как-то убедитесь, что вектор изначально содержит ровно один элемент, равный 5 (не более или более s), то ваши два бита кода делают то же самое. И в этом случае вам не нужен тест для it != v.end() в коде поиска-стирания, вы бы знали, что он не равен. Вы могли бы просто сделать v.erase(find(v.begin(), v.end(), 5)).

+0

hm, приятно упомянуть стандартную идиому стирания; но OP фактически только ** хочет ** удалить ** одно ** возникновение – codeling

1

Разницы будет то, что, если есть более чем одно значение, соответствующее данные одному, то remove решения будет двигаться все от несогласованных элементов до начала (спасибо Стив Джессопу за то, что он указал на комментарии). Только erase удалит первое их появление; и вы закончите с повторной сортировкой vector, содержащей один меньше заданного значения.

find - решение удалит только первое вхождение и не изменит порядок вектора.

+0

'remove' не переносит равные значения в конец, он перемещает не равные значения в начало. То, что осталось в конце, не указано. –

-1

Вы действительно попытались увидеть разницу?

В первой части коды, std::remove преобразует вектор, помещая все элементов, которые равны 5 до конца вектора и возвращает итератор к новым концу. Когда вы вызываете erase, вы удаляете первый элемент после нового конца. Вы, вероятно, хотите сделать:

vector<int>::iterator it = remove(v.begin(), v.end(), 5); 
v.erase(it, v.end()); 

Это удалит все элементы со значением 5.

Во втором примере, std::find находит первый элемент вектора, который равен 5, и возвращает итератор Это. Вызов erase удалит только этот элемент.

В этом отличие.

+0

Он вызывает одиночную версию стирания, поэтому только один элемент стирается. –

+0

Вызов 'erase' на первом фрагменте кода удаляет только первый из удаленных элементов. – Snps

+0

да, я заметил это, но вы, ребята, были слишком быстры, пока я редактировал свой ответ –

Смежные вопросы