开发者

Can I delete a item from std::list based on pointer value?

This code is written on fly, plz ignore syntax mistakes if any.

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 = &myLi开发者_JAVA百科st.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?

I want to delete the middle item in the list by its pointer (assume I have the pointer value).

I know I can iterate through the list and look for this pointer but is there a better way? Does STL provide a function to do it..Can I use remove_if() in this case to delete the item?


Instead of keeping a pointer to the object you want to remove, why not keep an iterator?

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

The remove_if algorithm doesn't actually remove anything, it just shifts stuff around. It has no knowledge of the container that the iterators point to. Of course the member function remove_if of std::list is a different thing altogether as pointed out in the comments.


Sure, list::remove_if uses whatever condition you give it. For example

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));

Mankarse's point is good though - if you can use an iterator instead of a pointer to identify the item you're interested in, then you don't need to mess about with this.

Beware also that we're relying here on the fact that the address of an item in a list stays the same forever. That isn't always true of all collections, for example vector might have to relocate all the data when you call push_back. If it does, then your middle item is no longer pointed to by item2. Each collection documents which operations can invalidate iterators and/or references to elements.


Instead of getting the back item, you could get the end iterator, make sure it's not begin, decrement by one to point to the last item, and then erase that iterator directly whenever you want.


I think remove_if is a little bit of overkill for what zadane is trying to do. All that needs to be accomplished is to save the location or value of an item in order to delete that specific item later.

As Mark suggested you can store the iterator to the object and use it to delete the item with an erase call, like below:

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);

Or, if your structure has the == operator defined for MY_STRUCT, you can store the value of the object itself and use the remove method

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

Of course if you make your list a list of pointers then you don't have to worry about the == operator as it is already defined for pointer types. Just make sure that if you're iterating through the list and call erase, you need to update your iterator with the returned value.

Also, the remove method removes all elements of the passed value, so if you only want to remove 1 item at a time save the iterator and not the value.

This code is untested so I welcome any corrections.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜