首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在std::set<unique_ptr>上迭代,如何跟踪要删除哪些?

在std::set<unique_ptr>上迭代,如何跟踪要删除哪些?
EN

Stack Overflow用户
提问于 2018-08-28 16:40:14
回答 3查看 344关注 0票数 1

我需要遍历class T的一些对象。

它们存储在std::set<std::unique_ptr<T>> tees中。

循环主体的主要用途是使用对象,但通过这样做,我还将了解某些对象何时不再需要并可以删除。

我使用基于范围的for循环来迭代unique_ptrs:

代码语言:javascript
复制
for (std::unique_ptr<T> & tee : tees)

我知道我不能在循环(UB)中调用tees.erase(tee)。因此,我应该收集助手集合中需要删除的unique_ptr。问题:指针是唯一的,因此我不能将它们复制到助手集合中。

我可以在std::set<T*>中收集原始指针,但是如何在循环之后使用这些指针从tees集合中删除匹配的unique_ptr?此外,当我在这个问题中使用智能指针时,再次收集原始指针会感到错误。

我可以切换到shared_ptr,但是只有为了删除对象才能共享指针。感觉不对。

我可以从基于范围切换到其他方面,比如自己处理迭代器,并在删除条目之前获得下一个迭代器。但是回到C++11之前的技术也是不对的。

我可以转到std::remove_if。(编辑:实际上我做不到。在本问题下面和所接受的答案下面的评论中解释。)循环的身体会移动到unary_predicateλ中。但是循环的主要目的不是决定是否应该删除对象,而是使用它们,修改它们。

最小阻力的方法似乎是回到迭代器处理,这样我甚至不需要一个助手集合。但我不知道你能不能帮我一个C++11-ish (或14,17)的解决方案?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-08-28 16:51:06

我不认为你能找到比

代码语言:javascript
复制
for(auto it = container.begin(), it != container.end();)
{
    //use *it here
    if(needs_to_be_erased)
        it = container.erase(it);
    else
        ++it;
}

由于std::set不提供对其元素的可变访问,任何类型的transformremove都无法工作。您必须构建一个迭代器容器,然后在处理完集合之后,遍历每个迭代器的容器,调用每个迭代器的erase

票数 4
EN

Stack Overflow用户

发布于 2018-08-28 16:57:25

我认为您可以将这些位置复制到一个新的数据结构中,并通过反向访问新的数据结构在另一个循环中删除这些项。

代码语言:javascript
复制
int counter =0;
vector<int> indices;
for (unique_ptr<T> & tee : tees)
{
    if (bCondition)
        indices.push_back(counter);
    counter++;
}

reverse(indices.begin(), indices.end());
for (int  i : indices)
    tees.erase(tees.begin() + i);
票数 0
EN

Stack Overflow用户

发布于 2018-08-28 18:47:23

不是一个确切的解决方案,但是如果你必须做很多事情,你可以为它做你自己的算法。我想这不是标准库中的原因,因为算法需要知道容器才能执行擦除。

所以你可以这样做:

代码语言:javascript
复制
template<typename Cont, typename Pred>
void erase_if(Cont& c, decltype(std::begin(c)) b, decltype(std::end(c)) e, Pred p)
{
    while(b != e)
    {
        if(p(*b))
            b = c.erase(b);
        else
            ++b;
    }
}

template<typename Cont, typename Pred>
void erase_if(Cont& c, Pred p)
    { erase_if(c, std::begin(c), std::end(c), p); }

那就把它叫做:

代码语言:javascript
复制
erase_if(tees, [](std::unique_ptr<int> const& up){
    // use up here...
    return (*up) & 1; // erase if odd number
});

代码语言:javascript
复制
erase_if(tees, std::begin(tees), std::end(tees), [](std::unique_ptr<int> const& up){
    // use up here...
    return (*up) & 1; // erase if odd number
});
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52062704

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档