Event listeners calls removeListener

Hey all

I’m not sure if this is more suitable to put into the GitHub (i.e. it’s a bug) or there’s a known workaround / correct pattern for this issue (hence forum).

Here’s the rub:

I have 3 classes:

  • Gui controller A
  • Gui element B (owned by A)
  • Interactive camera C (owned by B)

Right now both A and C are listening to ofEvents().keyPressed.
If the user presses delete, then:

  1. A deletes B
  2. This causes B to delete C
  3. In the destructor of C it removes the liseners to ofEvents().keyPressed

But this then causes a crash, because in ofEvents.h we have:

inline void notify(const void* sender, T & param){
	if(ofEvent<T,Mutex>::enabled && !ofEvent<T,Mutex>::functions.empty()){
		std::vector<of::priv::Function<T>*> functions_copy; // (--1--)
			std::unique_lock<Mutex> lck(ofEvent<T,Mutex>::mtx);
			std::transform(ofEvent<T,Mutex>::functions.begin(), ofEvent<T,Mutex>::functions.end(),
					[&](of::priv::Function<T>&f){return &f;});
		for(auto & f: functions_copy){
			if(f->function(sender,param)){ //(--2--)
				throw ofEventAttendedException();

notice (–1--), where it creates a copy of all the functions its going to call before calling them one by one.

So, what happens is that it notify caches a list of functions it wants to call, one of those calls removeListener (which makes functions_copy), then notify continues to call functions in the list functions_copy. And at (–2--) we get…Ker-ash!!!

@arturo - this seems to be your party from the git history? Is there a workaround (other than leaving a flag to do the deletion next frame or something like that. but that would still happen on the update listener somehow so can’t see how it solves the problem)

mmh, are you using latest master? i fixed this some time ago and now that copy is using shared_ptr so the copies are still there until the event is notifed but the functions are disabled if you delete one while notifying so they are not being called either

Thanks for quick reply!

i just updated to current master
the issue pops up elsewhere now


	inline bool notify(const void*s,T&t){
		std::unique_lock<Mutex> lck(mtx);
			return function(s,t); // <<-- here function is empty
		}catch(std::bad_function_call &){
			return false;

ah ok, actually it’s safe.
the right exception is thrown and caught

i just had my debugger in paranoid mode (break on any exception thrown) and didn’t realise (thought it was showing unhandled exceptions)

thank you, false alarm : )