What alternatives does one have to the following code for performing safe asynchronous callbacks on an object?
class MyClass : public std::enable_shared_from_this<MyClass>
{
private:
void fetchResults()
{
std::weak_ptr<MyClass> weakSelf = shared_from_this();
m_service.getResultAsync(
/* args... */,
/* Callback */
[weakSelf](Result r)
{
auto self = weakSelf.lock();
if (self)
{
self->workFinishedWithResult(std::move(r));
}
});
}
void workFinishedWithResult(Result r) { // ... continue workflow }
std::shared_ptr<Service> m_service;
};
I would like to avoid using enable_shared_from_this
(and avoid clients of m_service
requiring it for what is a very common use case), but it seems difficult to extend the lifetime of MyClass
once inside the callback without it.
Capturing this
in the lambda instead and trying to deregister it in MyClass' destructor, or preventing MyClass from being destructed until the callback is finished is a path that leads to races, deadlocks and a loss of simplicity. I'm almost certain that capturing 'this' can't be made safe.
It seems if MyClass is asking a shared_ptr<Service>
to call it back, it can only guarantee that it remains valid if it can manage or extend its own lifetime (via enable_shared_from_this
) since it doesn't know how long the callback will live for. Otherwise it would have to be the responsibility of whoever owns MyClass
, or whoever knows the lifetime of both the Service
and MyClass
to deal with this, but it all becomes very error-prone and impractical.
It seems the only viable solutions are:
- Use
enable_shared_from_this
with the "capture weakly" pattern (as in the above code) - Have MyClass be given a
Service&
so it is the caller's responsibility to ensure the service outlives it. - Use a static method/function as the callback and pass everything it needs in by-value (problem is that sometimes you really do want to pass control back into
MyClass
and you have the same problem).
What are the alternatives here? Or does using enable_shared_from_this
just become inevitable when doing async C++?
Aucun commentaire:
Enregistrer un commentaire