-
Notifications
You must be signed in to change notification settings - Fork 62
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Problems using smart pointers #6
Comments
That's interesting, there is an implicit conversion between
That's also interesting,
It outputs 2 (not 3) when I run your example and that's expected because your promise chain is not terminated at this point, so all your promises still exist. When reaching the finally handler, there are 2 references of the shared pointer: one in the promise returned by That's because QObject::connect(reply, &QNetworkReply::finished, [=]() {
reply->disconnect(SIGNAL(finished()));
if (reply->error() == QNetworkReply::NoError) {
// ...
}); I will need to find a way to release the captured promise in |
yes. disconnect is right!. |
Sounds good! I will try to add support for QPromise<QByteArray> download(const QUrl& url)
{
return QPromise<QByteArray>([&](
const QPromiseResolve<QByteArray>& resolve,
const QPromiseReject<QByteArray>& reject) {
QNetworkReply* reply = manager->get(QNetworkRequest(url));
QObject::connect(reply, &QNetworkReply::finished, [=]() {
if (reply->error() == QNetworkReply::NoError) {
resolve(reply->readAll());
} else {
reject(reply->error());
}
reply->deleteLater();
});
});
} |
I also stumbled over the problem of the lambda lifetimes in conjunction with QObject::connect. It's too easy to create promises from signals the wrong way due to the fact that Qt signals/connect isn't really designed for the promise pattern. With QNetworkReply it works out fine because the reply object itself is designed as a kind of promise. You usually delete it directly after finished and everything is fine because Qt tears down all connections. If your source is a persistent QObject and you want to build promises resolved/rejected by its signals, things get a bit more complicated. Without a "QObject sacrifice" for tearing down connections, you have to manually keep track of all signal connections and disconnect them after resolve/reject to free promise references and any other resource you may have captured. I ended up doing something like this: // -- promise-returning method --
auto connections = ConnectionGuard::create();
return QPromise<void>([&](const auto& resolve, const auto& reject) {
// Resolve on signal1
*connections << connect(this, &Class::signal1, this, [=]() {
resolve();
});
// Reject on signal2
*connections << connect(this, &Class::signal2, this, [=]() {
reject();
});
// Reject on signal3 if condition is met
*connections << connect(this, &Class::signal3, this, [=]() {
if (condition) reject();
});
}).finally([=]() {
connections->disconnect();
}); implemented like this pwuertz@09a709e I don't know if that is the most beautiful solution, but it does the job for quite a few use cases. QtPromise already knows how to transform futures into promises. Maybe it is possible to create an adapter for building promises from signals as well? Something like this? return QtPromise::fromSignals({
{object, &Class::resolveSignal1},
{object, &Class::resolveSignal2},
}, {
{object, &Class::rejectSignal1},
{object, &Class::rejectSignal2},
}); |
@pwuertz I already thought about integrating with Qt signals but didn't find a great API yet. I was thinking of The lambda lifetimes issue should be relatively easy to fix though, we need to release the promise in |
The way I understand the situation it is that the promise references held by If I make sure that all connections tied to the promise are disconnected after resolve/reject, the If this is true, this also means that you cannot construct a race of signals by composition of promises. A race-promise made from Maybe this is a situation where an intrinsic cancellation mechanism is required, but from what I read the people doing the promise specs came to the conclusion that a generic cancellation method is difficult/impossible to define. Maybe I'm completely wrong on this since these promise patterns are quite new for me. But please tell me if such discussions go beyond the scope of what you are willing to invest in this project (which is indeed nicely done!). |
I think it is: these are the only two objects, related to the generated promise, that can be captured in the signal lambda, so if we clear the internal promises when one of them get called, no more reference on the promise data will be held by the connection. Once fixed, the race approach would work, but you right, it's not the same as handling multiple signals in only one promise. The cancellation feature is already in my mind but it's not an easy one (I would like to implement the bluebird "don't care" approach).
It's fine, that's good for a project to receive feedback and external point of views. Though, it may be better to kickoff these discussions in separate tickets. I have a pretty long todo list on which many items are waiting for a decent API (and of course the time to implement it). However, there are a few features I will not implement, such as deferred or progress. |
Both issues reported in this ticket should now be resolved and will be released in version 0.4
@pwuertz would you mind to checkout master and verify if fa987a5 fixes the situation you described in this comment: the promise (and thus its data) should now be released as soon as it get resolved, even if the |
I can verify that this does not solve the problem I was referring to, and you seem to be aware of it mentioning that the signal connection used for resolving the promise is still alive. My point was that this connection keeps I'll create a new issue for discussions about qt-signal-helper ideas. |
I agree, we need an API to integrate with Qt signals since resources captured by the lambda will not be released as long as the connection lives (which is your point). fa987a5 wasn't intended to fix it but only the reported issue which was that the You right, auto-disconnecting would fix that issue too but it doesn't only concern signal/slot but all cases where +1 for a qt-signal-helper specific ticket. |
Released in 0.4.0 |
its has error in vs2015
So I switched to shared_ptr.
typedef std::shared_ptr< QNetworkReply > NetworkReplyPtr;
its compile is done. but not delete QNetworkReply.
I want to use QSharedPointer to destroy it when QPromise is done.
Please help me.
The text was updated successfully, but these errors were encountered: