6

I'm attempting to write a an observer pattern in c++ so I have a map that contains eventname -> vector of callback functions

The callback functions are stored in a vector as

std::function<void(void *)>

so the map looks like

std::unordered_map<std::string, std::vector<std::function<void(void *)>>>

I can add listeners to the vector and receive and respond to event notifications. My problem is with implementing detach.

So std::function's can't be compared, so erase/remove is out, so I wanted to search the vector and compare manually.

I found that this question had success using std::function::target with getting access to underlying pointers, but I can't use this, since I'm using std::bind to initialize the callback:

std::function<void(void *)> fnCallback = std::bind(&wdog::onBark, this, std::placeholders::_1)

I just want to compare the underlying member function ptrs, or even comparison with the underlying object ptr to which the member function is associated. Is there any way?

I'd like to avoid wrapping the member fn ptr in an object that contains a hash, although it looks like I might have to go that way...

Community
  • 1
  • 1
stack user
  • 835
  • 1
  • 9
  • 28
  • 2
    Could you post an example on how you want to add/remove items from the map? – Holt Sep 22 '16 at 08:15
  • It appears to me that you already know the answer... :-) – skypjack Sep 22 '16 at 08:15
  • 1
    You can't really do it without also storing a pointer to the object in question to use as a key. My impl uses weak_ptr and checks the collection to remove expired() before dispatch of the event. Attach is (shared_from_this(), &class::member), detach is (shared_from_this()). – Robinson Sep 22 '16 at 08:20
  • An example would be too long (templates and multiple files), sorry Holt. – stack user Sep 22 '16 at 08:30

1 Answers1

2

When I do this, I return a token to the listening code.

My usual pattern is to have a weak_ptr<function<sig>> in the broadcaster, and the token is a shared_ptr<void> (to the stored weak ptr).

When broadcasting, I filter out dead targets, then broadcast. Targets deregister by simply clearing, destroying or otherwise discarding their token. A vector of tokens in their instance is a reasonable way if they want to never deregister.

If you never broadcast this can lead to old dead resources hanging around needlessly, so in a public framework I might want something with bettter guarantees. But it is lightweight easy and fast otherwise.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524