2015-02-25 3 views
-1

В чем разница между erase() и remove()?Почему std :: whatever :: erase() метод и std :: remove() автономная функция?

  • std::whatever::erase - принимает итераторы диапазона (первый-последний) и соответствует всем элементам.
  • std::remove - принимает итераторы диапазона (первый-последний) и значение, соответствующее удалению.

Помимо этого, похоже, что они делают то же самое. то есть фактическое «стирание» или «удаление» одинаково в обоих случаях (если только я не ошибаюсь). Итак, почему один из них - метод (вектор, множество, карта и т. Д.), А другой - свободно плавающая функция?

Примечания:

  • Да, я знаю, есть также erase(), который принимает один итератор, но точно так же могут оказывать std::remove() с той же семантикой.
+2

Это хорошо объясняется на [Erase/Удалить Idiom] (http://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom) на wikipedia. – Borgleader

ответ

7

Стирание или удаление не такое же.

erase действительно удаляет предметы из коллекции.

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

Другими словами, если вы начали с 1, 2, 1, 3, и сделал remove(..., 1) вы бы в конечном итоге с коллекцией, содержащей 2, 3, x, x, где x означает некоторое неизвестное значение (может быть перемещен из-значения, так что, если они были строки они может превратиться в пустые строки).

Когда все сделано, он возвращает итератор в положение первого x. Если вы хотите удалить эти предметы из коллекции, вы вызываете collection.erase(returned_iterator, collection.end()) (иначе, идиома remove/erase).

В случае, если вы заботитесь Почему все так, одна причина в том, что std::remove работает с итераторами. Итератор разрешает доступ к элементам в контейнере, но не к самому окружающему контейнеру. Таким образом, невозможно удалить std::remove элементы из контейнера, даже для контейнеров, которые поддерживают это (и не все).

+0

Эти «х» на самом деле неуточнены? –

+0

@ DieterLücking: у них нет заданных значений - небрежно, я не помню, действительно ли они «неуказанные» или «неопределенные». В любом случае вы не знаете их точной стоимости. –

3

std::remove фактически не уничтожает элементы в контейнере. Скорее, это «все элементы, удовлетворяющие определенным критериям из диапазона, и возвращает итератор прошлого конца для нового конца диапазона.

Удаление выполняется путем сдвига (посредством присвоения перемещения) элементов в диапазоне таким образом, что элементы, которые не быть удалены появляются в начале диапазона. Относительный порядок оставшихся элементов сохраняется и физические размеры контейнера не изменяются.- http://en.cppreference.com/

Move присваивание покидает перемещенные переменный в допустимом но неустановленном состоянии, так что он может или не может быть оставлен без изменений.

Чтобы фактически удалить элементы из контейнера, вам необходимо позвонить erase.

Вот конкретный пример:

#include <iostream> 
#include <algorithm> 
#include <vector> 

void printVector(const std::vector<int>& v) 
{ 
    for (auto i : v) { 
     std::cout << i << ' '; 
    } 
    std::cout << std::endl; 
} 

int main() 
{ 
    std::vector<int> v { 0, 1, 2, 1, 3, 4 }; 

    printVector(v); // Prints 0 1 2 1 3 4 

    // Shift elemnts that aren't to be removed to the beginning of container 
    const auto newEnd = std::remove(v.begin(), v.end(), 1); 

    printVector(v); // Prints 0 2 3 4 * * 

    // Erase the unwanted elements 
    v.erase(newEnd, v.end()); 

    printVector(v); // Prints 0 2 3 4 

    return 0; 
} 

Live example

0

std::removestd::remove_if) представляет собой общий алгоритм назначения, которые могут быть применены (также) в массивы. Элементы массивов не могут быть стерты. Размеры массивов фиксированы. Вы можете только «стирать» элементы в массиве до хвоста. А массивы не имеют методов. Вы можете использовать только общие функции с массивами.

Способ erase определенных пользователем (то есть стандартных) контейнеров действительно стирает элементы контейнера. Более того, этот метод делает безусловное стирание элементов.

Учтите, что для стирания элементов из контейнера вам необходимо знать детали реализации контейнера. Таким образом, это объясняет, почему стирание определяется как метод контейнеров.

В свою очередь стандартные алгоритмы std::remove и std::remove_if реализуют общий алгоритм перемещения «стертых» элементов. Им не нужно знать детали реализации контейнера, к которому они привязаны.

Кроме метод стирания классов std::list и std::forward_list также имеют свои собственные методы remove и remove_if, что напротив общих алгоритмов std::remove и std::remove_if стирания элементов из списка в соответствии с некоторыми условиями (аналогично стандартным алгоритмам std::remove и std::remove_if).

Рассмотрим следующий пример, чтобы увидеть разницу между общим алгоритмом std::remove и методом remove класса std::list

#include <iostream> 
#include <algorithm> 
#include <list> 

int main() 
{ 
    std::list<int> l = { 1, 10, 2, 3, 10, 4 }; 

    std::cout << "size of the list is " << l.size() << std::endl; 
    for (int x : l) std::cout << x << ' '; 
    std::cout << std::endl;  

    std::remove(l.begin(), l.end(), 10); 

    std::cout << "\nsize of the list is " << l.size() << std::endl; 
    for (int x : l) std::cout << x << ' '; 
    std::cout << std::endl;  

    l = { 1, 10, 2, 3, 10, 4 }; 

    l.remove(10); 

    std::cout << "\nsize of the list is " << l.size() << std::endl; 
    for (int x : l) std::cout << x << ' '; 
    std::cout << std::endl;  

    return 0; 
} 

Выход программы

size of the list is 6 
1 10 2 3 10 4 

size of the list is 6 
1 2 3 4 10 4 

size of the list is 4 
1 2 3 4 
Смежные вопросы