$include_dir="/home/hyper-archives/boost-users/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-users] [signals2] Usage (lifespan) question
From: Nat Goodspeed (nat_at_[hidden])
Date: 2009-03-05 11:44:08
I'd like suggestions for an API designed around Boost.Signals2. This 
isn't performance-critical.
Assume a publish class containing a boost::signals2::signal. This 
class's listen() method is a thin wrapper around signal::connect(). 
Using boost::bind, I can listen() with any method (with appropriate 
signature) on any class.
I'm trying to introduce the concept of filter objects. Each filter is 
itself a publish object. Client logic composes a chain from some publish 
object through zero or more filters to the ultimate listener. A filter 
passes along to its own listeners some subset of the input notifications.
The central issue is the lifespan of a filter object. I want the filter 
objects in such a chain implicitly freed when the ultimate listener 
disconnects.
Approach 1
==========
I could achieve that by managing each filter object with shared_ptr, 
storing a copy in each listener. When the last listener is destroyed, 
the filter goes away. (This assumes passing weak_ptr to boost::bind() so 
the connection itself doesn't keep the listener alive. Further assume 
I've used connection::track() so that the signal to which the filter is 
connected implicitly disconnects.) Naturally this effect cascades 
"upstream" through the filter chain.
But it bothers me that such an implementation imposes new requirements 
on each listener. Beyond declaring a method with the right signature, 
the listener must now store a shared_ptr to the publish object to which 
it's listening. That implies a method on the listener to capture the 
shared_ptr and establish the connection. Therefore, every listener must 
be derived from some particular base class, and explicit connection and 
disconnection must be done through the listener rather than directly 
through the publish object.
Either this new inverted API must apply to all publishers/listeners, or 
client logic must distinguish between the case of connecting to a filter 
and connecting to any other type of publish object.
It feels to me as though this approach has gone into the weeds.
Approach 2
==========
Instead of passing a filter's weak_ptr to boost::bind() to the publish 
object's listen() method, I could instead pass the filter's shared_ptr. 
Now the publish object upstream from the filter is responsible for the 
filter's lifespan: when the filter explicitly disconnects, it will 
(eventually) go away. It will not implicitly disconnect because it won't 
go away as long as the connection still holds a copy of its shared_ptr.
(Frank says[1] he might tweak the library to forget a shared_ptr 
immediately on disconnect, but currently it survives for a while.)
Consider a chain:
A is the original publish object
B is a filter listening to A
C is the ultimate listener, listening to B
Again, the goal is to disconnect B (thus deleting it) when C disconnects 
or is destroyed.
We could make B store its connection object to A. The question is, how 
would B know to disconnect it? How could B become aware of C 
disconnecting from B's signal object?
Approach 3-n
============
Suggestions? Thanks!
[1] 
http://www.nabble.com/Re%3A--signals2--review--The-review-of-the-signals2-library-(formerly-thread_safe_signals)-begins-today%2C-Nov-1st-p22102367.html