std::multiset 定义比较器,用于插入和比较

std::multiset define comparator for insertion and comparison

提问人:Nubcake 提问时间:4/26/2020 最后编辑:Nubcake 更新时间:7/26/2021 访问量:527

问:

我正在使用指向对象的 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;

但是,当涉及到擦除多集中的元素时,调用删除所有具有相同深度的元素,这是不希望的。我尝试了这个问题中的建议:在 std::multiset 中,如果找到一个元素,是否有函数或算法可以仅擦除一个样本(unicate 或 duplicate),erase

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

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

是否可以在没有升压的情况下为 std::multiset 定义 2 个比较器?(如何在此多组上设置两种比较器(一种用于插入,一种用于查找)?一个用于插入,一个用于比较?

谢谢

编辑: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++ 指针 std 多集

评论


答:

2赞 jignatius 4/26/2020 #1

问题出在这条线上:

m_Renderables.erase(renderable);

这将擦除具有相同值的所有元素。

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

m_Renderables.erase(iterator);

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

评论

0赞 Nubcake 4/26/2020
谢谢,那是我的错别字。我已经编辑了我的答案以显示我的解决方案。
0赞 jignatius 4/26/2020
@Nubcake 虽然有效,但多组会更快。作为一般规则,您应该更喜欢容器的功能,而不是使用 or 因为它们针对其容器进行了优化。std::find_iffind()find()std::find()std:find_if()
0赞 Nubcake 4/26/2020
我使用的原因是将迭代器返回到它找到的第一个值(在这种情况下,有 3 个具有相同深度的元素),但它并不总是正确的对象,所以我必须检查下一个具有相同深度的元素是否是我正在寻找的对象。有没有更好的解决方案?std::find_iffind()
0赞 jignatius 4/26/2020
@Nubcake 您可以使用 std::multiset::equal_range 返回一对迭代器,表示具有特定值的元素的第一个和最后一个迭代器。然后,您可以使用这些迭代器进行循环,在擦除正确的元素之前先检查元素。
0赞 Vitalik Beloded 7/26/2021 #2

您可以将 std::set 与 comparer 一起使用,而不是多集,如下所示:

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