按标识从列表中删除对象

时间:2011-06-19 22:35:36

标签: c++

在下面的示例中,std :: list存储Resource类型的对象(按值,不指向)。 Resource类不提供小于比较也不提供相等运算符。通过标识(也称为内存地址)删除对象的好方法是什么。我可以以某种方式避免O(n)吗? std :: list是否是正确的容器?

// 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;
    }
}

编辑:假设Resource类实现了移动语义。此外,资源会通过一种选择器(cp.epoll或java.nio.Selector)为事件通知重新注册任何“移动”。

3 个答案:

答案 0 :(得分:2)

您将Resource个副本存储在容器中,因此稍后按地址查找元素没有多大意义。
您可以做的是保存list::iterator,因为list具有以下属性:任何操作都不会使迭代器无效,从而明确擦除迭代器(或清除整个list)。

答案 1 :(得分:1)

编辑:抱歉,不要理会这个答案 - 如果您确定只删除最多一个元素,那么您的循环就可以了。


不管是通过内存地址进行比较是否合理,但是在循环中使用list::erase,您必须稍微改写它以避免增加无效的迭代器:

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

如果您没有其他要求而不是按地址查询,则可以始终只生成std::setstd::unordered_set个元素,并将Resource::operator<()实现为指针比较。

无论哪种方式,它们都有某些条件可以作为STL容器成员;正如评论中所述,这些条件是否适用于您的Resource课程?否则你可以只创建一个std::shared_ptr<Resource>的容器并使用它内置的比较器,例如制作一个std::unordered_set<std::shared_ptr<Resource>>

答案 2 :(得分:0)

“std :: list是正确的容器吗?”

我对此表示怀疑。如果此类不提供比较运算符,您仍可以自己提供

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

然后您可以使用std::set<resource, resourcecomparator>