通过引用从 std::list 中删除元素

remove element from std::list by reference

std::list<Reader> readers;

readers.push_back(Reader());

Reader& r = *(readers.begin());

/* at this point, the exact place in list, where the reader was picked out, is forgotten. 
   Only 'r' shows which element of the list it is. */

readers.erase(r); //<---how to do this?

客户端从 manager/dispatcher 获取新实例 'reader' 对象。如果 "everyone interested" 通过观察调度的 reader 池来拾取缓存数据,则管理器会维护一个已调度内容的内部列表。invalidates/frees。

当客户端不再对数据感兴趣时,它应该return reader 向管理器请求从池中移除。但我不希望客户端保留迭代器——它对管理器的胆量和 readers 的池绝对不感兴趣;只需要它拥有 reader 它得到的,而不是指向它的迭代器。因此,对于删除,它会调用管理器的清理功能,并引用该单个 reader.

有没有更好的方法从列表中删除 reader 而不是遍历整个列表以搜索 reader 引用导致的那个?

结合使用std::removeerase

readers.erase(std::remove(readers.begin(), readers.end(), r), readers.end());

此外,您不能在不迭代的情况下按值从列表中删除元素。如果您考虑一下,它甚至没有意义,因为列表 中的指针必须 更新。

如果您只有对象的引用,您的选择是使用 std::list::remove

readers.remove(r);

std::find 结合 std::list::erase

readers.erase(std::find(readers.begin(), readers.end(), r));

前者要遍历整个列表,而后者会在找到第一个元素时停止,然后将其删除。对于大型列表,这可能会有很大的不同。

这两个选项仅在项目唯一时才有效。如果你有非唯一元素,那么你可以使用 std::find_if 并提供一个比较项目地址的仿函数。这样你可以保证你只删除引用实际引用的对象而不是比较等于。

readers.erase(std::find_if(readers.begin(), readers.end(), [&](const auto& e) {return &r == &e;}));

你可以比较指针来检查它们是否是同一个对象

readers.remove_if([r=&r](auto& x){return &x==r;});

如果列表可以包含相等的值,那么您可以执行如下操作

#include <iostream>
#include <list>

int main()
{
    struct Reader { std::pair<char, int> p; };
    std::list<Reader> readers;

    readers.push_back({{ 'A', 1 } });
    readers.push_back({ { 'A', 2 } });
    Reader &rr = readers.back();
    readers.push_back({ { 'A', 3 } });

    readers.remove_if([&rr](const Reader &r) { return &r == &rr; });

    for (const auto &r : readers)
    {
        std::cout << r.p.first << ' ' << r.p.second << std::endl;
    }

    return 0;
}

程序输出为

A 1
A 3