Reputation: 2317
As I understand it, the way to handle exceptions happening inside the event loop in Qt is to override QApplication::notify() and handle it there. I have tried that and it works:
class Application : public QApplication
{
Q_OBJECT
public:
explicit Application( int& argc, char** argv );
// override to handle out of memory exceptions
bool notify( QObject* receiver, QEvent* e );
signals:
public slots:
private:
char* m_buffer;
};
Application::Application(int &argc, char **argv)
:QApplication( argc, argv )
{
m_buffer = new char[1024*1024];
}
bool Application::notify(QObject *receiver, QEvent *e)
{
try
{
return QApplication::notify( receiver, e );
}
catch( std::bad_alloc& )
{
if ( m_buffer )
{
delete[] m_buffer;
m_buffer = NULL;
}
// calling QMessageBox from here doesn't work
// even if release a load of reserved memory
// don't know why
QMessageBox::critical( NULL, "Exception", "Application out of memory" );
}
But the message box is blank when it appears (i.e. not rendered correctly). I thought perhaps the process didn't have enough memory. So I tried allocating 1MB of memory at the start (see m_buffer above) and then releasing it before the QMessageBox displayed. But that didn't work either. Any ideas?
Upvotes: 0
Views: 1523
Reputation: 3843
I could be interpretting QApplication::notify wrong, but I'm getting the impression that you're attempting to create a GUI object (QMessageBox) when the Qt event loop crashes. I don't believe that's possible.
For exception safety, my understanding is that you have to wrap the whole QApplication::exec function with a try-catch sequence, as in the Exception Safety docs.
Consider implementing a custom error handler using qCritical and qWarning. I like to redirect those functions to a log file in my temp directory to debug crashes. Of course, your program still crashes unlike in exception handling, but at least you know why. I can provide example code if necessary.
Upvotes: 1
Reputation: 25155
QMessageBox::exec(), which is used by the static convenience methods critical(), warning(), etc., opens a local event loop and only returns to the main event loop once the message box is closed. Local event loops are nasty in general, opening in the midst of event handling (QApplication::notify) is even more so. You better use QDialog::open to open the message box without blocking, or even better, defer the message box:
In your application class:
Q_INVOKABLE void showMessage( const QString& message ); // in your Application class, does the QMessageBox::critical() call
Instead of calling QMessageBox::critical() directly, replace it by something like this:
QMetaObject::invokeMethod( this, "showMessage", Qt::QueuedConnection, Q_ARG(QString, "Application out of memory") );
Upvotes: 0