Способ, который я предпочитаю при работе с boost asio :
Я столкнулся с той же проблемой при работе с boost asio . Нам нужно зарегистрировать обратные вызовы для io_service
, и было трудно реализовать какой-то класс Manager
, который управляет временем жизни объектов, которые мы можем создать.
Итак, я реализую то, что было предложено Майкл Кейсс в cppcon2016. Я начал передавать shared_ptr
объекту std::bind
.
Я использовал для продления времени жизни объекта, и в обратном вызове вы можете либо снова продлить время жизни объекта (путем повторной регистрации обратного вызова), либо автоматически разрешить d ie.
std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>();
auto func = std::bind(&MyClass::MyMemFunc, this, ptr);
ptr.reset();
В контексте библиотеки, обеспечивающей обратные вызовы для асинхронных данных, как мы должны предотвращать функции обратного вызова, указывающие на nullptr?
Я бы не сказал это лучшее решение, но, используя мой вышеописанный подход, вы можете определить, нужно ли вам продолжить обратный вызов или нет.
Это может быть неэффективный способ, но он не вызовет неопределенного поведения.
void CallbackContainer::rawTest(const std::string& some_data, std::shared<CallbackContainer> ptr)
{
if (ptr.use_count() == 1) {
// We are the only owner of the object.
return; // and the object dies after this
}
std::cout << data_ << " " << some_data << std::endl;
}
РЕДАКТИРОВАТЬ:
Пример кода, который показывает, как это сделать, используя std :: enable_shared_from_this :
#include <iostream>
#include <memory>
#include <functional>
class ABCD: public std::enable_shared_from_this<ABCD> {
public:
void call_me_anytime()
{
std::cout << "Thanks for Calling Me" << std::endl;
}
public:
ABCD(void)
{
std::cout << "CONSTRUCTOR" << std::endl;
}
~ABCD(void)
{
std::cout << "DESTRUCTOR" << std::endl;
}
};
int main(void)
{
auto ptr = std::make_shared<ABCD>();
auto cb = std::bind(&ABCD::call_me_anytime, ptr->shared_from_this());
ptr.reset();
std::cout << "RESETING SHARED_PTR" << std::endl;
std::cout << "CALLING CALLBACK" << std::endl;
cb();
std::cout << "RETURNING" << std::endl;
return 0;
}
Вывод:
CONSTRUCTOR
RESETING SHARED_PTR
CALLING CALLBACK
Thanks for Calling Me
RETURNING
DESTRUCTOR