简体   繁体   English

使用指针从列表中删除项目

[英]Remove item from a list using its pointer

I have a pointer p (not an iterator) to an item in a list. 我有一个指针p (不是迭代器)到列表中的项目。 Can I then use p to delete (erase) the item from the list? 我可以使用p从列表中删除(擦除)项目吗? 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. 到目前为止,我只能通过遍历列表直到我到达位置p处的项目,然后使用erase方法来执行此操作,这看起来非常低效。

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. std::list不是关联的,所以你无法使用指针作为键直接删除特定元素。

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. 如果可能,您可以将列表更改为std::multiset (假设存在重复项),这将使直接访问更有效。

  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. 如果这是线性搜索的唯一一点,并且集合不大(<20项说。)为了方便起见,只需按照你的建议进行线性搜索,但在代码中留下一个大的注释,表明你是如何“ 完全得到 “这是多么低效。 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. 我猜这3可能是你最好的选择。 :) :)

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> . 有一种不可移植的方法可以从T*指针到list<T>的元素创建一个迭代器。 You need to look into your std library list header file. 您需要查看您的std库list头文件。 For Gnu g++ it includes stl_list.h where std::list definition is. 对于Gnu g++它包含stl_list.h ,其中std::list定义是。 Most typically std::list<T> consists of nodes similar to this: 最典型的std::list<T>由类似于此的节点组成:

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. 有了指向Node<T>::item指针,你可以使用offsetof计算这个节点指针。 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. 请注意,此Node模板可能是std::list的私有部分,因此您必须破解它 - 假设通过定义具有不同名称的相同struct模板。 std::list<>::iterator is just wrapper over this node . std::list<>::iterator只是这个node包装器。

It cannot be done. 它无法完成。

I have a similar problem in that I'm using epoll_wait and processing a list of events. 我有类似的问题,因为我正在使用epoll_wait并处理事件列表。 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. 事件结构只包含一个联合,其中最明显的类型是void *,用于指示找到的哪些数据(包括文件描述符)。

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. std :: list不允许你通过指针删除元素似乎真的很愚蠢,因为显然有一个下一个和前一个指针。

I'm considering going back to using the Linux kernel LIST macros instead to get around this. 我正在考虑重新使用Linux内核LIST宏来解决这个问题。 The problem with too much abstraction is that you have to give up on interoperability and communication with lower level apis. 抽象过多的问题是你必须放弃与低级api的互操作性和通信。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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