简体   繁体   中英

Remove item from a list using its pointer

I have a pointer p (not an iterator) to an item in a list. Can I then use p to delete (erase) the item from the list? Something like:

mylist.erase(p);

So far I have only been able to do this by iterating through the list until I reach an item at the location p , and then using the erase method, which seems very inefficient.

Nope, you'll have to use an iterator. I don't get why getting the pointer is easier than getting an iterator though...

A std::list is not associative so there's no way you can use a pointer as a key to simply delete a specific element directly.

The fact that you find yourself in this situation points rather to questionable design since you're correct that the only way to remove the item from the collection as it stands is by iterating over it completely (ie linear complexity)

The following may be worth considering:

  1. If possible, you could change the list to a std::multiset (assuming there are duplicate items) which will make direct access more efficient.

  2. If the design allows, change the item that you're pointing to to incorporate a 'deleted' flag (or use a template to provide this) allowing you to avoid deleting the object from the collection but quickly mark it as deleted. Drawback is that all your software will have to change to accommodate this convention.

  3. If this is the only bit of linear searching and the collection is not big (<20 items say.) For the sake of expediency, just do the linear search as you've suggested but leave a big comment in the code indicating how you " completely get " how inefficient this is. You may find that this does not become a tangible issue in any case for a while, if ever.

I'm guessing that 3 is probably your best option. :)

This is not what I advice to do, but just to answer the question:

Read only if you are ready to go into forbidden world of undefined behavior and non-portability:

There is non-portable way to make an iterator from T* pointer to an element in a list<T> . You need to look into your std library list header file. For Gnu g++ it includes stl_list.h where std::list definition is. Most typically std::list<T> consists of nodes similar to this:

template <class T>
struct Node {
   T item;
   Node* prev;
   Node* next;
};

Having pointer to Node<T>::item you can by using offsetof calculate this node pointer. Be aware that this Node template could be the private part of std::list so you must hack this - let say by defining identical struct template with different name. std::list<>::iterator is just wrapper over this node .

It cannot be done.

I have a similar problem in that I'm using epoll_wait and processing a list of events. The events structure only contains a union, of which the most obvious type to use is void * to indicate which data is relevant (including the file descriptor) that was found.

It seems really silly that std::list will not allow you to remove an element via a pointer since there is obviously a next and previous pointer.

I'm considering going back to using the Linux kernel LIST macros instead to get around this. The problem with too much abstraction is that you have to give up on interoperability and communication with lower level apis.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM