Add an example of error handling of QFuture without using exceptions
Also fixed a few unrelated typos in docs. Task-number: QTBUG-83236 Change-Id: I776cda8f0ef4de6c4a93e94092dc19e94d1884c8 Reviewed-by: Vitaly Fanaskov <vitaly.fanaskov@qt.io> Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
This commit is contained in:
parent
300aaec2f9
commit
339dd743a9
@ -72,3 +72,30 @@ i.toBack();
|
|||||||
while (i.hasPrevious())
|
while (i.hasPrevious())
|
||||||
qDebug() << i.previous();
|
qDebug() << i.previous();
|
||||||
//! [2]
|
//! [2]
|
||||||
|
|
||||||
|
//! [3]
|
||||||
|
using NetworkReply = std::variant<QByteArray, QNetworkReply::NetworkError>;
|
||||||
|
|
||||||
|
enum class IOError { FailedToRead, FailedToWrite };
|
||||||
|
using IOResult = std::variant<QString, IOError>;
|
||||||
|
//! [3]
|
||||||
|
|
||||||
|
//! [4]
|
||||||
|
QFuture<IOResult> future = QtConcurrent::run([url] {
|
||||||
|
...
|
||||||
|
return NetworkReply(QNetworkReply::TimeoutError);
|
||||||
|
}).then([](NetworkReply reply) {
|
||||||
|
if (auto error = std::get_if<QNetworkReply::NetworkError>(&reply))
|
||||||
|
return IOResult(IOError::FailedToRead);
|
||||||
|
|
||||||
|
auto data = std::get_if<QByteArray>(&reply);
|
||||||
|
// try to write *data and return IOError::FailedToWrite on failure
|
||||||
|
...
|
||||||
|
});
|
||||||
|
|
||||||
|
auto result = future.result();
|
||||||
|
if (auto filePath = std::get_if<QString>(&result)) {
|
||||||
|
// do something with *filePath
|
||||||
|
else
|
||||||
|
// process the error
|
||||||
|
//! [4]
|
||||||
|
@ -51,9 +51,31 @@
|
|||||||
|
|
||||||
QFuture provides a \l{Java-style iterators}{Java-style iterator}
|
QFuture provides a \l{Java-style iterators}{Java-style iterator}
|
||||||
(QFutureIterator) and an \l{STL-style iterators}{STL-style iterator}
|
(QFutureIterator) and an \l{STL-style iterators}{STL-style iterator}
|
||||||
(QFuture::const_iterator). Using these iterators is another way to access
|
(QFuture::const_iterator). Using these iterators is another way to access
|
||||||
results in the future.
|
results in the future.
|
||||||
|
|
||||||
|
If the result of one asynchronous computation needs to be passed
|
||||||
|
to another, QFuture provides a convenient way of chaining multiple
|
||||||
|
sequential computations using then(). Additionally, onFailed() can be used
|
||||||
|
to handle any failures that occurred in the chain. Note that QFuture relies
|
||||||
|
on exceptions for the error handling. If using exceptions is not an option,
|
||||||
|
you can still indicate the error state of QFuture, by making the error type
|
||||||
|
part of the QFuture type. For example, you can use std::variant, std::any or
|
||||||
|
similar for keeping the result or failure or make your custom type.
|
||||||
|
|
||||||
|
The example below demonstrates how the error handling can be done without
|
||||||
|
using exceptions. Let's say we want to send a network request to obtain a large
|
||||||
|
file from a network location. Then we want to write it to the file system and
|
||||||
|
return its location in case of a success. Both of these operations may fail
|
||||||
|
with different errors. So, we use std::variant to keep the result
|
||||||
|
or error:
|
||||||
|
|
||||||
|
\snippet code/src_corelib_thread_qfuture.cpp 3
|
||||||
|
|
||||||
|
And we combine the two operations using then():
|
||||||
|
|
||||||
|
\snippet code/src_corelib_thread_qfuture.cpp 4
|
||||||
|
|
||||||
QFuture also offers ways to interact with a runnning computation. For
|
QFuture also offers ways to interact with a runnning computation. For
|
||||||
instance, the computation can be canceled with the cancel() function. To
|
instance, the computation can be canceled with the cancel() function. To
|
||||||
pause the computation, use the setPaused() function or one of the pause(),
|
pause the computation, use the setPaused() function or one of the pause(),
|
||||||
@ -347,7 +369,7 @@
|
|||||||
\sa takeResult(), result(), resultAt(), results(), resultCount(), isValid()
|
\sa takeResult(), result(), resultAt(), results(), resultCount(), isValid()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* \fn template <typename T> std::vector<T> QFuture<T>::takeResult()
|
/*! \fn template <typename T> std::vector<T> QFuture<T>::takeResult()
|
||||||
|
|
||||||
Call this function only if isValid() returns \c true, otherwise
|
Call this function only if isValid() returns \c true, otherwise
|
||||||
the behavior is undefined. This function takes the first result from
|
the behavior is undefined. This function takes the first result from
|
||||||
@ -369,12 +391,12 @@
|
|||||||
\sa takeResults(), result(), results(), resultAt(), isValid()
|
\sa takeResults(), result(), results(), resultAt(), isValid()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* \fn template <typename T> std::vector<T> QFuture<T>::isValid() const
|
/*! \fn template <typename T> bool QFuture<T>::isValid() const
|
||||||
|
|
||||||
Returns true if a result or results can be accessed or taken from this
|
Returns \c true if a result or results can be accessed or taken from this
|
||||||
QFuture object. Returns false after the result was taken from the future.
|
QFuture object. Returns false after the result was taken from the future.
|
||||||
|
|
||||||
\sa takeResults(), takeResult(), result(), results(), resultAt()
|
\sa takeResults(), takeResult(), result(), results(), resultAt()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*! \fn template <typename T> QFuture<T>::const_iterator QFuture<T>::begin() const
|
/*! \fn template <typename T> QFuture<T>::const_iterator QFuture<T>::begin() const
|
||||||
|
Loading…
Reference in New Issue
Block a user