2

I have a std::multimap where values are of type std::function. Since there is no comparison for std::function - see this - it seems to be no way to remove a specific element from this multimap. I guess the same is true if you'd like to, for example, remove an element by value from e.g. a std::list or std::vector.

My use case is a function which takes a callback an argument (std::function). The callback should be called when a specific event occurs. However, there could be other circumstances where the callee want to 'deregister' the callback before it have fired.

Initially I though, let me just wrap the std::function in a struct and insert pointers to this struct in my map. However, this didn't prove feasible as the interface user shouldn't have to wrap callbacks in a struct and store pointer values.

The best idea I have at the moment is returning an id when the callback is registered - which must be stored if the callee want's t to have the option to cancel the callback later on.

Any ideas on my pickle?

Community
  • 1
  • 1
Alexander Olsson
  • 1,908
  • 1
  • 15
  • 24
  • Your "id" suggestion is what I would do. – Marshall Clow Mar 17 '13 at 01:02
  • 1
    `std::multimap` doesn't invalidate iterators on insertion / erasing so you could just store the iterator of a newly inserted element, and use it for erasing the element. Even though I don't know `std::multimap`very well, I use this method regularly for `std::list` and this works like a charm. Since the constraints on iterators seem to be the same I see no reason why it shouldn't work unless I missed some detail. – syam Mar 17 '13 at 01:16
  • I've ended up combining these two comments. I return an id, and the id I return is the iterator which "holds" the entry in the multimap. This makes removing very easy `mulitmap.erase(it)`. I also typedef'd the iterator so that it is something like `class::id_t`. Thank you for the input – Alexander Olsson Mar 18 '13 at 09:43
  • I extracted the code which spawned the original question to a library, it can be found here: https://github.com/noseglid/libde – Alexander Olsson Jul 11 '13 at 09:46

1 Answers1

0

If the caller is supposed to keep some kind of token (id in your case), why not just wrap the std::function in a std::shared_ptr and let the caller provide/keep that instead of some made-up ID? The std::multimap would then store the std::shared_ptr<std::function<...>> as its value directly instead of the std::function.

That way, you can easily remove it later and you will not copy the std::function itself around, which might also be a potentially costly operation. When the caller uses std::make_shared<std::function<...>>(...) it could be a real alternative IMHO.

Community
  • 1
  • 1
Daniel Frey
  • 55,810
  • 13
  • 122
  • 180
  • If you store a shared_ptr, how is the client supposed to remove it? – doctorlove Jul 05 '13 at 10:01
  • I don't think this is correct. If one place sharing a pointer makes it nullptr, the other place will still have it's previous view of the ptr - that's the point of shared, surely? – doctorlove Jul 05 '13 at 12:09
  • @doctorlove I think you are missing the point. What I proposed is supposed to solve the initial problem the OP asked about (and it does that). It does open up a certain potential of misuse, but that is beyond the scope of this. My answer was meant to give a start to the OP to overcome `std::function`'s lack of a comparison operator. – Daniel Frey Jul 05 '13 at 15:10