Search code examples
c++boost-signals2

How can I prevent signals2::scoped_connection from aborting in disconnect()?


I'm using boost::signals2 and have a connection management issue. I'm storing scoped_connections in a list that is later pruned. However, I have found that if the object owning the associated signal has been destroyed, scoped_connection::disconnect() aborts because several of its fields are now invalid.

signals2::connection conn =
    client->connectRequest( RequestSignal::slot_type(
        bind( &Manager::requestRefresh, this, _1 ) ).track( client ) );
mClients.push_back( ClientConnection( client, conn ) );

ClientConnection:

struct ClientConnection
{
    weak_ptr<Client> client;
    signals2::scoped_connection* connection;

    ClientConnection( weak_ptr<Client> aClient, signals2::connection aConnection )
    {
        client = aClient;
        connection = new signals2::scoped_connection( aConnection );
    }

    ~ClientConnection()
    {
        delete connection;
    }
}

The Manager class owns a list of these ClientConnections and periodically iterates through and attempts to delete entries from which it can't obtain a legit shared_ptr to the client. I've now learned that track() doesn't disconnect the connection when its object expires like I thought it would; it just prevents the signal from firing. When the client goes out of scope, the scoped_connection ends up pointing to a bunch of bad memory and I end up with prefetch or data aborts when it executes disconnect().

Is there something in the signals2 API that I have overlooked that can correct this issue? Or do I have to rethink my connection management? I know it seems odd to have to maintain connections to clients' signals from this end, but it's possible for the stream that the client consumes to go out of scope, so in that case I need to disconnect the Manager's slot from the client.


Solution

  • It turns out this is an object lifetime issue, not a signals2 issue. I used a raw pointer to the scoped connection to get around its noncopyable property. But what I overlooked is that when the struct is copy constructed as it's inserted into the list, the original is destroyed, which deletes the pointer's memory...

    Changing it to a shared pointer fixed this issue.