【问题标题】:std::multiset define comparator for insertion and comparisonstd::multiset 为插入和比较定义比较器
【发布时间】:2020-08-09 10:08:55
【问题描述】:

我正在使用 std::multiset 指向对象的指针来在我的游戏中实现 Z 排序,因此我不需要在每次插入时对结构进行排序。我使用比较器按对象的深度插入:

struct rendererComparator
{
    bool operator ()(const Renderable* r1, const Renderable* r2) const
    {
        return r1->depth < r2->depth;
    }
};

std::multiset<Renderable*, rendererComparator> m_Renderables;

但是,当涉及到擦除多重集中的元素时,对erase 的调用会删除所有具有相同深度的元素,这是不可取的。我尝试了这个问题的建议:In std::multiset is there a function or algorithm to erase just one sample (unicate or duplicate) if an element is found 但是

auto iterator = m_Renderables.find(renderable);
if (iterator != m_Renderables.end())
{
    m_Renderables.erase(renderable);
}

由于比较器,仍然会擦除所有具有相同深度的元素。

是否可以在没有 boost 的情况下为 std::multiset 定义 2 个比较器? (How can I set two kind of comparator (one for insert, one for find) on this multiset?) 一个用于插入,一个用于比较?

谢谢

编辑:Jignatious 指出我没有擦除迭代器(我的错字)。我通过使用std::find_if解决了它

auto iterator = std::find_if(m_Renderables.begin(), m_Renderables.end(), [renderable](const Renderable* r1) { return r1 == renderable; });
if (iterator != m_Renderables.end())
{
    m_Renderables.erase(iterator);
}

【问题讨论】:

    标签: c++ pointers set std multiset


    【解决方案1】:

    问题出在这一行:

    m_Renderables.erase(renderable);
    

    它会删除 所有 具有 相同值的元素

    您需要使用 find() 函数调用中的迭代器进行擦除。这将删除迭代器指向的单个元素:

    m_Renderables.erase(iterator);
    

    请注意,std::multiset::find() 返回一个迭代器,该迭代器指向在多重集中搜索的元素的下界(或第一个)(如果存在),否则返回结束元素迭代器之后的那个。

    【讨论】:

    • 谢谢,这是我的错字。我已经编辑了答案以显示我的解决方案。
    • @Nubcake 虽然std::find_if 可以工作,但multiset 的find() 会更快。作为一般规则,您应该更喜欢容器的find() 函数而不是使用std::find()std:find_if(),因为它们针对容器进行了优化。
    • 我使用std::find_if 的原因是find() 将迭代器返回到它找到的第一个值(在这种情况下,有3 个具有相同深度的元素)但它并不总是正确的对象所以我必须检查下一个具有相同深度的元素是否是我正在寻找的对象。有没有更好的解决方案?
    • @Nubcake 您可以使用std::multiset::equal_range 返回一对迭代器,表示具有特定值的元素的第一个和最后一个迭代器。然后您可以使用这些迭代器进行循环,在删除正确的元素之前先检查元素。
    【解决方案2】:

    您可以将 std::set 与比较器一起使用,而不是 multiset,如下所示:

    struct Element
    {
        int value;
    
        Element(int v)
        {
            value = v;
        }
    
        bool operator() (Element* const& left, Element* const& right) const
        {
            if (left->value == right->value)
                return (left < right);
    
            return left->value < right->value;
        }
    };
    
    

    它将像多映射一样存储多个值,但在擦除时没有“全部擦除”,在插入时不替换相同的值,并且通过引用正确查找。

    
    std::set<Element*, Element> set;
    set.insert(new Element(10));
    auto last = new Element(10);
    set.insert(last); // 10 10 like in multiset
    set.erase(last); // will delete proper references
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-02
      • 2010-11-06
      • 1970-01-01
      相关资源
      最近更新 更多