std::remove is not removing from std::vector
Here is my issue:
In my GUI, there are several types of listeners. They are stored in std::vector<WhateverListener*>
In my GUI, I have a method called removeListeners
and it looks like this:
void Widget::removeListeners( Widget* widget )
{
removeFocusListener((FocusListener*)widget);
removeMouseListener((MouseListener*)widget);
removeKeyboardListener((KeyboardListener*开发者_StackOverflow)widget);
removeWidgetListener((WidgetListener*)widget);
}
Basically, I do not think it should matter how I cast it; they are just pointers. I think std::remove
simply compares pointers, therefore if I provide a widget* then it shouldn't affect anything (I think).
How the remove functions look is something like this:
void Widget::removeWidgetListener(
WidgetListener *listener )
{
widgetListeners.erase(
std::remove(widgetListeners.begin(),
widgetListeners.end(), listener),
widgetListeners.end());
}
So, in the Widget destructor, I iterate through the widget's children and call removeListeners()
:
Widget::~Widget(void)
{
for(std::vector<Widget*>::iterator it = getChildBegin();
it != getChildEnd(); ++it)
{
(*it)->removeListeners(this);
(*it)->parentWidget = NULL;
(*it)->_container = NULL;
}
}
It does not work. After calling delete on a Widget which was listening to its children, the children still had listeners.
However, if I call the remove
methods directly, and the widget inherits from the listener, it works:
Widget::~Widget(void)
{
for(std::vector<Widget*>::iterator it = getChildBegin();
it != getChildEnd(); ++it)
{
(*it)->removeWidgetListener(this);
(*it)->parentWidget = NULL;
(*it)->_container = NULL;
}
}
So why does one work and not the other? The only difference I spot is that in the first one I'm casting a Widget to that type. But I thought it would just compare pointers and if they were == it would remove it?
I'm afraid you might be getting stung by object identity and virtual base classes in C++
http://www.parashift.com/c++-faq-lite/multiple-inheritance.html
Basically, converting pointers to polymorphics bases, is not guaranteed to result in identical pointer values (when cast to (void*) e.g.).
It should work as long as you store the exact same pointer type as what you cast it to during removal, but I can't be sure without looking at more of your code/widget class hierarchy.
The root of your issue seems to be an incorrect design. The need to cast as you are doing implies that the function is in the wrong place. It's not clear from your post what the relationship between Widgets and the different types of Listener classes are.
You need to rethink where you are calling the removeListeners function from and instead of putting it in the base class destructor, you should put it in the destructor of the class that actually knows which type of listener it is (and only call the correct one).
It's hard to be more specific without getting some more detail on the relationships between your classes. In general, if you have to cast, you should ask yourself if there is a better way to accomplish what it is that's forcing you to cast.
精彩评论