Reputation: 469
I'm using a std::multiset of pointers to objects to implement Z-ordering in my game, so I don't need to sort the structure on each insertion. I use a comparator for insertion by the object's depth:
struct rendererComparator
{
bool operator ()(const Renderable* r1, const Renderable* r2) const
{
return r1->depth < r2->depth;
}
};
std::multiset<Renderable*, rendererComparator> m_Renderables;
However when it comes to erasing an element in the multiset, the call to erase
removes all elements which have the same depth which is undesirable. I tried the suggestions in this question: In std::multiset is there a function or algorithm to erase just one sample (unicate or duplicate) if an element is found but
auto iterator = m_Renderables.find(renderable);
if (iterator != m_Renderables.end())
{
m_Renderables.erase(renderable);
}
Still erases all the elements with the same depth because of the comparator.
Is it possible to define 2 comparators for std::multiset without boost? (How can I set two kind of comparator (one for insert, one for find) on this multiset?) One for insertion and one for comparison?
Thanks
Edit: Jignatious pointed out that I wasn't erasing the iterator (typo by me). I solved it by using 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);
}
Upvotes: 1
Views: 579
Reputation: 1
Instead of multiset, you can use std::set with comparer like this:
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;
}
};
It will store multiple values like multimap, but without 'erase all' on erase, without replace same values on insert and with proper find by reference.
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
Upvotes: 0
Reputation: 6484
The problem is on this line:
m_Renderables.erase(renderable);
which erases all elements with the same value.
You need to erase with the iterator from the find()
function call instead. That will erase the single element that the iterator points to:
m_Renderables.erase(iterator);
Note that std::multiset::find()
returns an iterator pointing to the lower bound (or first) of the elements which is searched in the multiset if it exists, otherwise the one past the end element iterator.
Upvotes: 2