Connect with unique objects
vainamon opened this issue · comments
Hello!
Thanks for the useful nice little tool.
Consider the following example:
class other_class
{
public:
other_class() = default;
other_class(int v) : nr(v) {}
void clicked()
{
xil_printf("clicked:");
}
void clicked_again(int v)
{
xil_printf("clicked_again:");
}
private:
int nr = 23;
};
class my_class
{
public:
my_class(int f) : mf(f) {}
void some_method()
{
emit click();
}
miso::signal<> click;
int mf = 0;
};
int main() {
my_class src(56);
my_class src2(5656);
other_class dst(4);
other_class dst2(100500);
miso::connect(src.click, std::bind(&other_class::clicked, dst));
miso::connect(src2.click, std::bind(&other_class::clicked, dst2));
src.some_method();
return 0;
}
Slot clicked() will be called twice, which is unexpected, but is not surprise - because of static nature of SHT in connect_i function. For solve this I replace static SHT sh
to
static std::unordered_map<std::string, SHT> sh_hash;
auto sh_key = typeid(T).name() + std::string(typeid(FT).name()) + static_cast<std::ostringstream&>(
std::ostringstream().flush() << reinterpret_cast<void*>(&sholders)
).str();
SHT &sh = sh_hash[sh_key];
But there is another problem if objects dynamically and repeatedly created, connected, emitted and destroyed: sh_hash would not be cleared and would be overfull sometime. That is why I changed connect_i function to:
template<class T, class FT, class SHT>
void connect_i(T &&f, std::vector<common_slot_base *> &sholders, bool active = true) {
static std::unordered_map<std::string, SHT> sh_hash;
auto sh_key = typeid(T).name() + std::string(typeid(FT).name()) + static_cast<std::ostringstream&>(
std::ostringstream().flush() << reinterpret_cast<void*>(&sholders)
).str();
SHT &sh = sh_hash[sh_key];
func_and_bool<FT> fb{std::make_shared<FT>(std::forward<T>(f)), active, reinterpret_cast<void *>(&f)};
bool already_in = false;
bool active_status = active;
std::for_each(sh.slots.begin(), sh.slots.end(),
[&](func_and_bool<FT> &s) { if (s.addr == fb.addr){s.active = active; already_in = true;} active_status |= s.active; });
if (active_status) {
if (!already_in) sh.slots.emplace_back(fb);
if (std::find(sholders.begin(), sholders.end(), static_cast<common_slot_base *>(&sh)) == sholders.end()) {
sholders.push_back(&sh);
}
} else {
remove(sholders.begin(), sholders.end(), static_cast<common_slot_base *>(&sh));
sh_hash.erase(sh_key);
}
}
That's all.
Hi,
Thanks for taking time to fix this issue, indeed the problem you have reported is a valid and serious one. I would be happy to have it fixed, so, in case you would open a pull request, I would be happy to have it merged back, and considering the amount of code you have wrote for this, I'd be happy to add you as a project developer too if you want this, using the motto: "more eyes see more!"!
Cheers, f.
Ok, I would open a pull request. And of course these changes must be reviewed and tested by someone else. I think there's no need for add me as a project developer - I'll plan to use miso in my projects and if there's another issues, then I'll be definitely let you know.