I have the following code that deletes the signal during one of the callbacks from the signal:
#include <iostream>
#include <boost/signals2/signal.hpp>
struct Foo {
boost::signals2::signal<void(int)> signal;
};
std::vector<Foo> foos;
foos.emplace_back(Foo());
std::vector<int> values;
auto connection = boost::signals2::scoped_connection(foos[0].signal.connect([&](int x) {
foos.clear(); // delete the foos here, where we will be calling from below
values.emplace_back(1);
}));
foos[0].signal(1);
std::cout << "values.size()=" << values.size() << "\n";
Have I just been lucky in this "working" (as in it is undefined behaviour) or is there some magic pointer counting in signals2 that is stopping me from blowing my feet off?
That's a misleading comment. The deletion (
clear()) only happens after raising the signal, so the control flow is in the reverse order from the lines of code.To me, this code looks valid, unless you destroy
connection(e.g.connection.release();) from insde the signal handler. Even then it could be safe, but it would depend on the implementation details of handler iteration. I suspect it will still be fine, because the Signals2 library is expressly thread-aware, so the converse MUST be fine (adding handlers to the same slot during signal invocation).The magic reference counting in Signals2 is the bit you already have:
scoped_connection, which will automatic disconnect when the last copy goes out of scope.Here's my take on the code which passes UBsan/ASan both with and without optimizations:
Live On Coliru
Prints