
Peter Dimov wrote:
My old (and reiterated) suggestion was to eliminate all the tracking complexity on the signal side and just make the invocation disconnect a slot when it throws bad_weak_ptr. We can make mem_fn convert a weak_ptr argument to a shared_ptr (by abusing get_pointer for weak_ptr) to cover the typical bind( &X::f, wp, ... ) case.
That would effectively mean removing the tracking functionality and introducing an exception handling policy to the signal (which could be extended to other/all types of exceptions, made configurable or parameterizable with a suitable template argument) instead. The downside of it is that it loads off the burden to ensure correct results on the exception safety of the client code (which is usually less well tested than the library code) and additionally makes finding potential problems more difficult, because exceptions are silently swallowed by the signal invocation.
This doesn't address your concern that dead slots are only detected when called, but is it really a problem in practice?
I gave one (perhaps a little exotic) example for a valid use of signals where this particular behaviour would disqualify it. In many other cases it could at least result in unexpectedly high memory usage. Think of a user interface that relays user input from permanent elements (like a menu entry) to numerous and often changing other elements (like list entries). For a menu item that's never triggered by the user, you'd get an ever-growing connection list with mostly dead connections. Boost.Signals already solves this problem sufficiently well, by only delaying the connection removal if the disconnect() call originates from the signal call context and retrying to clean up the entire list for every subsequent disconnect().
The remaining thread-safety problem is what happens when a signal is manipulated while being invoked, and are multiple concurrent invocations allowed. The nontrivial part is to solve it without making the invocation performance suffer horribly, which is what people love to benchmark. :-/
From a user perspective I'd expect invocations to work concurrently, while manipulations would require exclusive access, which shouldn't be too difficult to implement (read_write_mutex). I think the cost of invocations is what should be considered primarily (and not for the benchmark results), which is why I criticized the per-slot locking in Frank's implementation. But I agree with him that optimization is something for later. I saw a suggestion to make the thread-safety optional through a policy template parameter and that sounds fine to me. What about an allocator parameter, btw (as the signal is a slot container)? Regards Timmo Stange