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:
Sona Kurazyan 2020-04-17 09:39:35 +02:00
parent 300aaec2f9
commit 339dd743a9
2 changed files with 55 additions and 6 deletions

View File

@ -72,3 +72,30 @@ i.toBack();
while (i.hasPrevious())
qDebug() << i.previous();
//! [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]

View File

@ -54,6 +54,28 @@
(QFuture::const_iterator). Using these iterators is another way to access
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
instance, the computation can be canceled with the cancel() function. To
pause the computation, use the setPaused() function or one of the pause(),
@ -347,7 +369,7 @@
\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
the behavior is undefined. This function takes the first result from
@ -369,9 +391,9 @@
\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.
\sa takeResults(), takeResult(), result(), results(), resultAt()