Упаковка пространства имен Python ModuleNotFoundError

Что делает std :: remove do?

Вот псевдокод std::remove. Возьмите несколько секунд, чтобы узнать, что он делает, а затем прочитайте объяснение.

Iter remove(Iter start, Iter end, T val) {
    Iter destination = start;

    //loop through entire list
    while(start != end) { 
        //skip element(s) to be removed
        if (*start == val) { 
            start++; 
         }
         else //retain rest of the elements
             *destination++ = *start++;
     }

     //return the new end of the list
     return destination;
}

Обратите внимание, что удаление просто перемещает элементы в последовательности, переписывая значения, которые вы хотите удалить. Значит, ценности, которые вы хотели удалить, действительно исчезли, но тогда в чем проблема? Скажем, у вас есть вектор со значениями {1, 2, 3, 4, 5}. После вызова remove для val = 3 вектор теперь имеет {1, 2, 4, 5, 5}. То есть 4 и 5 были сдвинуты вверх так, что 3 ушло от вектора, но размер вектора не изменился. Кроме того, конец вектора теперь содержит дополнительную левую копию 5.

Что делает vector :: erase do?

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

erase(Iter first, Iter last)
{
    //copy remaining elements from last
    while (last != end())
        *first++ = *last++;

   //truncate vector
   resize(first - begin());
}

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

Идиома удаления стирания

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

//first do the remove
auto removed = std::remove(vec.begin(), vec.end(), val);

//now truncate the vector
vec.erase(removed, vec.end());

Это известно как идиома удаления-стирания. Почему он спроектирован так? Понимание заключается в том, что операция поиска элементов является более общей и независимой от базового контейнера (зависит только от итераторов). Однако операция стирания зависит от того, как контейнер хранит память (например, у вас может быть связанный список вместо динамического массива). Таким образом, STL ожидает, что контейнеры будут выполнять свою собственную стирание, одновременно предоставляя общую операцию «удалить», чтобы все контейнеры не могли реализовать этот код. На мой взгляд, это имя очень вводит в заблуждение, а std::remove должно было быть вызвано std::find_move.

Примечание: выше код строго псевдокод. Фактическая реализация STL более умна, например, используя std::move вместо копирования.

0
задан user1914139 4 March 2019 в 15:26
поделиться