Remove object from list by identity
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::iterator
s 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>
.
精彩评论