开发者

Remove object from list by identity

开发者 https://www.devze.com 2023-03-13 20:58 出处:网络
In the following example a std::list stores objects of type Resource (by value, not pointing to). The Resource class does not provide a less than comparison nor equality operator. What is a good way t

In the following example a std::list stores objects of type Resource (by value, not pointing to). The Resource class does not provide a less than comparison nor equality operator. What is a good way to remove an object by identity (aka memory address). Can i avoid O(n) somehow? Is std::list the right container?

// Definition of the container
std::list<Resource> resources;

// Code
Resource *closedResource = resourceFromList();
for (std::list<Resource>::iterator it = resources.begin(); it != resources.end(); ++it)
{
    if (closedResource == &*it)
    {
        resources.erase(it);
        break;
    }
}

Edit: Assume that the Resource class implements move semantic. Furthermore the Resource reregisters itself for any "movement" by a kind of Selector (cp. epoll or java.nio.Selector) for event not开发者_如何学Goifications.


You're storing Resource copies in the container, so later finding an element by address doesn't make much sense.
What you can do is save list::iterators since list has the property that iterators are not invalidated by any operation expect explicitly erasing that iterator (or clearing the entire list).


Edit: Sorry, never mind this answer -- if you are certain only to be removing at most one element, then your loop is fine.


Never mind whether comparing by memory address is sensible, but to use list::erase in a loop you have to write it a little differently to avoid incrementing an invalidated iterator:

for (std::list<Resource>::iterator it = resources.begin(); it != resources.end(); )
{
  if (want_to_erase)   it = resources.erase(it); // advances to the next position
  else                 ++it;
}

If you have no other requirements than look-up by address, you could always just make a std::set or std::unordered_set of elements and implement Resource::operator<() as pointer comparison.

Either way, there are certain conditions on types for them to be eligible as STL container members; as was asked in the comments, do those conditions apply to your Resource class? Otherwise you could just make a container of std::shared_ptr<Resource> and use its inbuilt comparators, and for example make an std::unordered_set<std::shared_ptr<Resource>>.


"Is std::list the right container?"

I doubt it. If this class does not provide a comparison operator you can still provide one yourself

struct resourcecomparation {
  const bool operator() (const Resource &l, const Resource &r) const;
}resourcecomparator;

and then you can use, for instance, an std::set<resource, resourcecomparator>.

0

精彩评论

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