If the Listener dies, should it call removeListener?


#1

I have a general newbie question regarding the implementation of the Observer pattern in Juce.

If SliderListener “A” listens to Slider “B” and “A” dies before “B”, this means “B” will try to notify dangling pointer (tell me if I’m wrong). Is there a reason why the SliderListener object does not keep track of the Sliders it is listening to in order to unregister itself on destruction ?

Something like this:

void Slider::addListener (SliderListener* const listener) throw() { jassert (listener != 0); if (listener != 0) { listeners.add (listener); listener->addNotificationSource (this); } }


#2

The reason is just that it’s trivial to do it manually and I’ve never thought it’s worth the extra bloat of giving every listener an array. The listeners will always need to know about the slider that they’re interested in anyway, so will probably already have pointers to them - making them also contain another pointer to the same thing just seems like a waste.


#3

Ok, I get your point. I didn’t realize most apps behave like you describe (listeners already have pointers, relation between “model” and “view” is static). My Listeners are a bit different: they have no idea what GUI elements they are connected to so I’ll just give them an array… :smiley:


#4

I have a suggestion. Instead of giving an array to every listener why not pass it the instance of the slider it listens to. That way SliderListener can call “Slider::removeListener” from it’s destructor.

You can derive your class from SliderListener, Implement a method called setSlider and pass on the instance of the slider to listen to and in the destructor call removeListener using slider object.

Or you can also hold on to the slider object that you receive from the callbacks.


#5

That would not work since a SliderListener in my case will listen to many sliders.

I implemented my solution by subclassing Slider to ObservableSlider which inherits from oscit::Observable. The listener (which inherits from oscit::Observer) now has the following method:

void observe(ObservableSlider *slider) { append_and_hold(&sliders_, slider); slider->addListener(this); }

The method is called “observe” since it will be overloaded with different UI components. “sliders_” is a std::list<Observable*>.


#6

Okay, So you are dealing with a single listener and multiple broadcaster. In that case your approach is probably better.


#7

This would remove boilerplate and possible sources of error. I like this suggestion a lot.


#8

The well-known norwegian toolkit I used before uses guarded pointers for that purpose. I think if the listenerList would be an Array<WeakReference<SomeListener> > would remove all problems with dangling entries in the listener list (just removing nullptrs from time to time and check if not null in ListenerList::call).
And I bet Jules and Timur have some cute C++11 feature to make it even nicer, like if the list could drop nullptrs automatically…?


#9