Могу ли я удалить элемент из std :: list на основе значения указателя? - PullRequest
0 голосов
/ 08 сентября 2011

Этот код написан на лету, плз игнорировать синтаксические ошибки, если таковые имеются.

std::list<MY_STRUCT> myList;

MY_STRUCT theStruct;

myList.push_back( theStruct );
myList.push_back( theStruct );

// assume I store the pointer of the last item (the 2nd item in this case).
MY_STRUCT * item2 = &myList.back();

// I added another item
myList.push_back( theStruct );

// now I want to delete item2 that I stored bases on its pointer.
// Can myList.remove_if(...) help if so how?

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

Я знаю, что могу перебирать список и искать этот указатель, но есть ли лучший способ?Предоставляет ли STL функцию для этого ... Могу ли я использовать remove_if () в этом случае для удаления элемента?

Ответы [ 4 ]

4 голосов
/ 08 сентября 2011

Вместо того, чтобы держать указатель на объект, который вы хотите удалить, почему бы не оставить итератор?

std::list<MY_STRUCT>::iterator item2 = --mylist.end();

Алгоритм remove_if на самом деле ничего не удаляет, он просто перемещает объекты.Он не знает контейнера, на который указывают итераторы.Конечно, функция-член remove_if из std :: list - это совсем другое, как указано в комментариях.

2 голосов
/ 08 сентября 2011

Вместо того, чтобы получить элемент back, вы можете получить итератор end, убедиться, что он не begin, уменьшить его на единицу, чтобы указать на последний элемент, а затем erase этот итератор напрямую, когда вы захотите. .

2 голосов
/ 08 сентября 2011

Конечно, list::remove_if использует любое условие, которое вы ему даете.Например,

template <typename T>
struct AddressIs {
    T *ptr;
    AddressIs(T *ptr) : ptr(ptr) {}
    bool operator()(const T &object) const {
        return ptr == &object;
    }
};

myList.remove_if(AddressIs<MY_STRUCT>(item2));

Идея Манкарса хороша - если вы можете использовать итератор вместо указателя для идентификации интересующего вас предмета, вам не нужно возиться с этим.1005 *

Также обратите внимание, что мы полагаемся здесь на тот факт, что адрес элемента в list остается неизменным всегда.Это не всегда верно для всех коллекций, например, vector может потребоваться переместить все данные при вызове push_back.Если это так, то на ваш средний элемент больше не указывает item2.Каждая коллекция документирует, какие операции могут сделать недействительными итераторы и / или ссылки на элементы.

0 голосов
/ 08 сентября 2011

Я думаю, что remove_if немного излишне из-за того, что задан пытается сделать. Все, что нужно сделать, это сохранить местоположение или значение элемента, чтобы позже удалить этот конкретный элемент.

Как предложил Марк, вы можете сохранить итератор для объекта и использовать его для удаления элемента с помощью вызова стирания, как показано ниже:

MY_STRUCT struct;
myList.push_back(struct);
myList.push_back(struct);
std::list<MY_STRUCT>::iterator del_it = myList.end() - 1;
myList.erase(del_it);

Или, если ваша структура имеет оператор ==, определенный для MY_STRUCT, вы можете сохранить значение самого объекта и использовать метод удаления

MY_STRUCT struct1;
MY_STRUCT struct2;
myList.push_back(struct1);
myList.push_back(struct2);
myList.remove(struct2);

Конечно, если вы сделаете свой список списком указателей, вам не нужно беспокоиться об операторе ==, так как он уже определен для типов указателей. Просто убедитесь, что если вы выполняете итерацию по списку и вызываете erase, вам необходимо обновить свой итератор возвращаемым значением.

Кроме того, метод remove удаляет все элементы переданного значения, поэтому, если вы хотите удалить только 1 элемент за раз, сохраните итератор, а не значение.

Этот код не проверен, поэтому я приветствую любые исправления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...