Вопрос

Я пишу программу, которая более или меньше, как это:

#include <list>

list<MyClass> things;

class MyClass {
   // some stuff

   void remove() {
       things.remove_if(THING_IS_ME);
   }
};

Что мне нужно написать вместо Thing_is_me?

Другими словами, я использую глобальный список STL как коллекцию вещей. В какой-то момент объект, который находится в списке, распознает, что это избыточно и хочет) получить себя удаленным из списка, а б) сам разрушается.

Как мне это сделать?

Я не написал C ++ около 15 лет и немного запутанный этой страницей здесь: http://www.cplusplus.com/Reeference/algorithm/remove_if/

Каковы эти предикаты? Сейчас C ++ имеет функции более высокого порядка?

Это было полезно?

Решение

(Первоначально набор комментариев, но переписан как ответ после обнаружения того, что он действительно хотел сделать.)

Вы понимаете, что магазин контейнеров STL копии Вещей, которые вы вставляете, верно? Это означает экземпляры MyClass лучше быть сопоставимым (например, через operator==) - Вы не можете просто сравнить адреса, поскольку они всегда будут разными.

Если наличие копий MyClass не имеет смысла, то вы, вероятно, лучше с Контейнер указателя.

Что говорят, язык C ++ использует копию-семантику по умолчанию. Язык требует, чтобы вы делали такие вещи, как ссылки, явные в коде. Я настоятельно рекомендую вам забрать Хорошая книга C ++ Или вы будете споткнуться по вопросам, подобным этому в будущем.

Другие советы

Все резко изменилось в C ++ за последние 15 лет. В июле 1994 года предложение Александра Степанова библиотеки, которая включает в себя свои идеи общего программирования, получила окончательное одобрение Комитета АНСИ / ISO. Эта библиотека, которую мы удобно называем сегодня, STL впоследствии стал стандартной библиотекой C ++. История STL примерно так же очаровательная, как идеи, и это определенно стоит читать.

То std::remove_if() Функция, которую вы нашли, - это просто другое отражение этой философии, которая стала частью современной идентичности C ++. Короче говоря, это общая функция, которая будет работать на любом контейнере (последовательности) элементов и с любым (вещь, которая действует как а) состояние. Для этого необходимо предоставить функцию две вещи:

  1. пара итераторы это разграничить диапазон элементов, на которых вы хотите работать;
  2. и а предикат Это, когда при вызове на элементе возвращается истина, если элемент должен быть удален и ложным в противном случае.

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

bool operator==(const MyClass& a, const MyClass& b)
{
    // return true if the two are equal, and false otherwise.
}

Затем мы можем использовать наш предикат для удаления элементов типа MyClass:

std::remove(things.begin(), things.end(), *this);  // if *this == elem

Напомним, что стандартная функция std::remove() работает Любые Контейнер, даже те, которые еще не были созданы. Поскольку каждый вид контейнера имеет свой собственный способ удаления элементов, эта функция не может действительно выполнить удаление, не зная детали реализации контейнера, на которой он работает. Так вместо этого, std::remove() Функция отключает элементы вокруг таких, что элементы «удалены» находятся в конце контейнера. Затем он возвращает итератор, указывающий на первый элемент последовательных элементов «удален».

typedef std::list<MyClass>::iterator iter;
iter first_removed = std::remove(things.begin(), things.end(), *this);

Наконец, мы действительно удаляем элементы, вызвав определенную функцию удаления контейнера, которая работает на одном положении в списке или в диапазоне последовательных элементов для удаления:

things.erase(first_removed, things.end());

Нередко видеть этот тип кода в одной строке:

things.erase(std::remove(things.begin(), things.end(), *this),
             things.end());

Все это может показаться подавляющим и сложным, но у него есть несколько преимуществ. Для одной вещи этот дизайн стандартной библиотеки поддерживает динамическое программирование. Это также позволяет стандартной библиотеке предлагать контейнеры с очень тонким интерфейсами, а также несколько бесплатных функций, которые работают на разных видах контейнеров. Это позволяет быстро создавать контейнер и мгновенно получить все функции стандартной библиотеки для работы с ним. В качестве альтернативы, это позволяет быстро написать общую функцию, которая мгновенно работает со всеми стандартными контейнерами - те, которые уже написаны, а те не написаны.

Во-первых, простая ручная петля:

for( list<MyClass>::iterator it = things.begin(); it != things.end(); /*  */ ) {
    if( qualifiesForDelete( *it ) ) {
        it = things.erase( it );
    }
    else {
        ++it;
    }
}

Во-вторых, используя remove_if алгоритм. remove_if быть алгоритмом, в отличие от члена функции list, не может на самом деле удалить любые элементы, скорее, он перемещает элементы, чтобы удалить в конце списка. Впоследствии erase должен быть вызван. Это очень важная идиома, Стереть-удалить идиома, это должно быть изучено.

things.erase( 
    remove_if( things.begin(), things.end(), deletionPredicate ), 
    things.end() 
);

куда deletionPredicate является функцией или объектом функции, который принимает один аргумент типа и возврат bool. Отказ Элементы для которых true возвращается считается удаленным.

То remove_if Функция принимает три параметра: два итераторы, которые определяют диапазон, на которой вы работаете, и предикат (функция тестирования, которая возвращает bool). Начальный итератор указывает на первый элемент, на котором вы хотите работать; Конец итератор указывает на элемент после последнего элемента в диапазоне.

В примере из страница вы связаны с, предикат - это линия кода, которая говорит

bool IsOdd (int i) { return ((i%2)==1); }

Чтобы ваш код сделать то, что вы хотите, вам нужно будет написать что-то вроде этого:

things.remove_if(things.begin(), things.end(), SomePredicateFunction);

и вы определили SomePredicateFunction нравится так (замена true С соответствующим тестом):

bool SomePredicateFunction (MyClass c) { return true; }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top