I'm using boost::signals and leaking memory when I try to connect multiple signals to a single slot_type. I've seen this same leak reported on various forums, but can't find any that mention the correct way to do this, or any workaround.
What I am trying to do:
I am trying to pass the result of boost::bind() into a function. In this function, I want to connect multiple signals to that result. The first connect works fine, but every connect after the first will leak a handle.
Here is some sample code:
typedef boost::signal0<void> LeakSignalType;
class CalledClass
{
/* ... */
void connectToSlots(LeakSignalType::slot_type &aSlot)
{
LeakSignalType *sig;
std::list<LeakSignalType*> sigList;
std::list<LeakSignalType*>::iterator sigIter;
for(int i = 0; i < 50; i++)
{
/*Connect signals to the passed slot */
sig = new LeakSignalType;
sig->connect(aSlot);
sigList.push_back(sig);
}
for(sigIter = sigList.begin(); sigIter != sigList.end(); sigIter++)
{
/* Undo everything we just did */
delete *sigIter;
}
sigList.clear();
/*Everything should be cleaned up now */
}
/* ... */
}
class CallingClass : public boost::signals::trackable
{
CalledClass calledInstance;
/* ... */
void boundFunction(int i)
{
/*Do Something*/
}
void connectSignals()
{
calledInstance.connectToSlots(boost::bind( &CallingClass::boundFunction, this, 1));
}
/* ... */
};
Now call CallingClass::connectSignals().
I expect that the call to connectToSlots will connect 50 signals to a single slot, then disconnect and clean up all of those signals. What actually happens is that 1 signal completely cleans up, then the remaining 49 partially clean up, but leak some memory.
What is the correct way to pass a slot into a function to use multiple times? Any help would be appreciated.
Thanks, Chris
I'm pretty sure it's a bug. If you collapse it down to a tiny example, e.g.:
and trace the allocations, you'll find that one object (a
boost::signals::detail::signal_base_impl::iterator) allocated at line 75 ofboost/lib/signals/src/signal_base.cppis not freed up.On the first
connect, this iterator is attached to a fresh connection object, wheresignal_datais NULL:On the second
connect, however, the same connection object is reused, and the same line blindly overwrites the original pointer value. The second object is cleaned up, but the first is not.As verification, a breakpoint in
signal_base_impl::slot_disconnected, the only place wheresignal_datais cleaned up, is only triggered once.I tracked this down in 1.39.0, but it looks like it's the same in 1.40.0.
You could modify
boost::signals::detail::signal_base_impl::connect_slotto clean up any previous iterator value it finds in thesignal_datafield of an existing connection, if you're comfortable making such a change and running a custom build of Boost.It might be better to just make sure you're only setting these up a fixed number of times and live with a few small memory leaks that you know won't grow over time.
Update:
I was going to submit this to the Boost bug tracker, but it's already there. This is a much smaller test case, however.
https://svn.boost.org/trac/boost/ticket/738
Opened 3 years ago, not assigned to any milestone :-[