Throwing from QFuture::onFailed()
-
Hi,
I am trying to throw an exception inside QFuture::onFailed()'s lambda, but it appears to catch the exception and presumably propagate it to other chained onFailed() functions that may follow.
Currently, my workaround is using
QTimer::singleShot(0, this, []() { throw std::runtime_error("Bye"); });
I am not sure if there is a guaranteed lower/upper-bound in terms of when exactly the singleShot() is executed, but if it happens to execute after onFailed() is done executing, then it successfully crashes the app.
Is there a better way of achieving this?
Thanks!
-
AFAIK, exceptions through Qt classes or signal/slot connections are not supported.
-
"Throwing an exception from a slot invoked by Qt's signal-slot connection mechanism is considered undefined behaviour, unless it is handled within the slot:"
See https://doc.qt.io/qt-6/exceptionsafety.html -
Hi,
I am trying to throw an exception inside QFuture::onFailed()'s lambda, but it appears to catch the exception and presumably propagate it to other chained onFailed() functions that may follow.
Currently, my workaround is using
QTimer::singleShot(0, this, []() { throw std::runtime_error("Bye"); });
I am not sure if there is a guaranteed lower/upper-bound in terms of when exactly the singleShot() is executed, but if it happens to execute after onFailed() is done executing, then it successfully crashes the app.
Is there a better way of achieving this?
Thanks!
@Don-Burner said in Throwing from QFuture::onFailed():
Hi,
I am trying to throw an exception inside QFuture::onFailed()'s lambda, but it appears to catch the exception and presumably propagate it to other chained onFailed() functions that may follow.
Currently, my workaround is using
QTimer::singleShot(0, this, []() { throw std::runtime_error("Bye"); });
I am not sure if there is a guaranteed lower/upper-bound in terms of when exactly the singleShot() is executed, but if it happens to execute after onFailed() is done executing, then it successfully crashes the app.
Singleshot versus repeating isn't of significance here. The important detail is that this is a 0 timer.
https://doc.qt.io/qt-6/qtimer.html#details:
As a special case, a QTimer with a timeout of 0 will time out as soon as possible, though the ordering between zero timers and other sources of events is unspecified.
Events are processed by the event loop. Execution timing depends on returning control to the loop, other events in the queue, and what processing those events involves. It's not a realtime oriented system.
Is there a better way of achieving this?
What's the end goal?
-
@Don-Burner said in Throwing from QFuture::onFailed():
Hi,
I am trying to throw an exception inside QFuture::onFailed()'s lambda, but it appears to catch the exception and presumably propagate it to other chained onFailed() functions that may follow.
Currently, my workaround is using
QTimer::singleShot(0, this, []() { throw std::runtime_error("Bye"); });
I am not sure if there is a guaranteed lower/upper-bound in terms of when exactly the singleShot() is executed, but if it happens to execute after onFailed() is done executing, then it successfully crashes the app.
Singleshot versus repeating isn't of significance here. The important detail is that this is a 0 timer.
https://doc.qt.io/qt-6/qtimer.html#details:
As a special case, a QTimer with a timeout of 0 will time out as soon as possible, though the ordering between zero timers and other sources of events is unspecified.
Events are processed by the event loop. Execution timing depends on returning control to the loop, other events in the queue, and what processing those events involves. It's not a realtime oriented system.
Is there a better way of achieving this?
What's the end goal?
@Jeremy-Katz-at-Volexity You are right, I should have been clear. In this instance a more readable way could be something like:
QMetaObject::invokeMethod(this, [future]() mutable { future.waitForFinished(); }, Qt::QueuedConnection);
I suppose there is no mechanism for me to give priority to this lambda in the event loop.
Either way, the end goal is to simply crash the program. As far as I know, if a QFuture is chained with QFuture::then(), any exception thrown is propagated to QFuture::onFailed(). What's frustrating is that QFuture::onFailed() also catches exceptions thrown within it. This makes it difficult to simply crash the program if we encounter an exception in either QFuture::then() or QFuture::onFailed().
-
@Jeremy-Katz-at-Volexity You are right, I should have been clear. In this instance a more readable way could be something like:
QMetaObject::invokeMethod(this, [future]() mutable { future.waitForFinished(); }, Qt::QueuedConnection);
I suppose there is no mechanism for me to give priority to this lambda in the event loop.
Either way, the end goal is to simply crash the program. As far as I know, if a QFuture is chained with QFuture::then(), any exception thrown is propagated to QFuture::onFailed(). What's frustrating is that QFuture::onFailed() also catches exceptions thrown within it. This makes it difficult to simply crash the program if we encounter an exception in either QFuture::then() or QFuture::onFailed().
@Don-Burner said in Throwing from QFuture::onFailed():
@Jeremy-Katz-at-Volexity You are right, I should have been clear. In this instance a more readable way could be something like:
QMetaObject::invokeMethod(this, [future]() mutable { future.waitForFinished(); }, Qt::QueuedConnection);
I suppose there is no mechanism for me to give priority to this lambda in the event loop.
Nothing simple and straightforward comes to mind.
Either way, the end goal is to simply crash the program. As far as I know, if a QFuture is chained with QFuture::then(), any exception thrown is propagated to QFuture::onFailed(). What's frustrating is that QFuture::onFailed() also catches exceptions thrown within it. This makes it difficult to simply crash the program if we encounter an exception in either QFuture::then() or QFuture::onFailed().
Is there a reason to avoid std::abort(), terminate(), exit(), etc?
-
@Don-Burner said in Throwing from QFuture::onFailed():
@Jeremy-Katz-at-Volexity You are right, I should have been clear. In this instance a more readable way could be something like:
QMetaObject::invokeMethod(this, [future]() mutable { future.waitForFinished(); }, Qt::QueuedConnection);
I suppose there is no mechanism for me to give priority to this lambda in the event loop.
Nothing simple and straightforward comes to mind.
Either way, the end goal is to simply crash the program. As far as I know, if a QFuture is chained with QFuture::then(), any exception thrown is propagated to QFuture::onFailed(). What's frustrating is that QFuture::onFailed() also catches exceptions thrown within it. This makes it difficult to simply crash the program if we encounter an exception in either QFuture::then() or QFuture::onFailed().
Is there a reason to avoid std::abort(), terminate(), exit(), etc?
@Jeremy-Katz-at-Volexity said in Throwing from QFuture::onFailed():
Is there a reason to avoid std::abort(), terminate(), exit(), etc?
I use std::set_terminate, so unhandled exceptions call my terminate handler.
Thank you (and @Asperamanca) for the help. I personally think QFuture::onFailed() should not catch exceptions silently. It would not be surprising if other people falsely assume that it doesn't.
Maybe this can be filed as a Suggestion via the Qt Bug Tracker...
-
@Jeremy-Katz-at-Volexity said in Throwing from QFuture::onFailed():
Is there a reason to avoid std::abort(), terminate(), exit(), etc?
I use std::set_terminate, so unhandled exceptions call my terminate handler.
Thank you (and @Asperamanca) for the help. I personally think QFuture::onFailed() should not catch exceptions silently. It would not be surprising if other people falsely assume that it doesn't.
Maybe this can be filed as a Suggestion via the Qt Bug Tracker...
@Don-Burner said in Throwing from QFuture::onFailed():
I use std::set_terminate, so unhandled exceptions call my terminate handler.
EDIT: I thought std::terminate() always called std::abort(). Turns out, it calls the current terminate handler. In short, calling std::terminate() within QFuture::onFailed() works, at least for my purposes. Thanks!