Function bind_weak
Usage
- Use
fastsignals::bind_weakinstead ofstd::bindto ensure that nothing happens if method called when binded object already destroyed - Pass pointer to T class method as first argument,
shared_ptr<T>orweak_ptr<T>as second argument - Example:
bind_weak(&Document::save(), document, std::placeholders::_1), wheredocumentis aweak_ptr<Document>orshared_ptr<Document>
Weak this idiom
The fastsignals::bind_weak(...) function implements "weak this" idiom. This idiom helps to avoid dangling pointers and memory access wiolations in asynchronous and/or multithreaded programs.
In the following example, we use weak this idiom to avoid using dangling pointer wehn calling print() method of the Enityt:
struct Entity : std::enable_shared_from_this<Entity>
{
int value = 42;
void print()
{
std::cout << "print called, num = " << value << std::endl;
}
std::function<void()> print_later()
{
// ! weak this idiom here !
auto weak_this = weak_from_this();
return [weak_this] {
if (auto shared_this = weak_this.lock())
{
shared_this->print();
}
};
}
};
int main()
{
auto entity = std::make_shared<Entity>();
auto print = entity->print_later();
// Prints OK.
print();
// Prints nothing - last shared_ptr to the Entity destroyed, so `weak_this.lock()` will return nullptr.
entity = nullptr;
print();
}
Using bind_weak to avoid signal receiver lifetime issues
In the following example, Entity::print() method connected to the signal. Signal emmited once before and once after the Entity instance destroyed. However, no memory access violation happens: once Entity destoryed, no slot will be called because bind_weak doesn't call binded method if it cannot lock std::weak_ptr to binded object. The second event() expression just does nothing.
#include <fastsignals/signal.h>
#include <fastsignals/bind_weak.h>
#include <iostream>
using VoidSignal = fastsignals::signal<void()>;
using VoidSlot = VoidSignal::slot_type;
struct Entity : std::enable_shared_from_this<Entity>
{
int value = 42;
VoidSlot get_print_slot()
{
// Here fastsignals::bind_weak() used instead of std::bind.
return fastsignals::bind_weak(&Entity::print, weak_from_this());
}
void print()
{
std::cout << "print called, num = " << value << std::endl;
}
};
int main()
{
VoidSignal event;
auto entity = std::make_shared<Entity>();
event.connect(entity->get_print_slot());
// Here slot called - it prints `slot called, num = 42`
event();
entity = nullptr;
// Here nothing happens - no exception, no slot call.
event();
}