Seite 1 von 1

Umgang mit Exceptions ?

Verfasst: 15. März 2010 14:08
von bernds
Hallo,

ich habe Probleme damit, wie Qt mit Fehlermeldungen und Ausnahmen umgeht.

Vor dem Umstieg von MFC auf Qt (z.Z. Qt 4.4.3, VS 2005, XP) habe ich
viel mit Exceptions (eigenen bzw. solchen aus Bibliotheken Dritter) gearbeitet
und möchte auch unter Qt den vollen Zugriff auf ihre Behandlung haben.

Zu den Problem im Detail:

Im Rahmen des Projekts existiert eine GUI-Applikation, bei deren Beendigung eine
Ausnahme angezeigt wird (MessageBox):

Programm.exe - Fehler in der Anwendung
Die Ausnahme "unknown software exception"(0x...) ist ... an der Stelle 0x...
afgetreten. Klicken Sie af "OK", um das Programm zu beenden.

Im Debugger lässt sich ablesen, dass es sich um einen 'stack overflow' handelt,
der im Umfeld der unregister-Methoden aus der boost serialization Bibliothek erzeugt wird.

Solange ich die Ursache nicht beseitigen kann, möchte ich die MessageBox durch eine stream-Ausgabe ersetzen können.
Zur Behebung des Fehlers können später auch Informationen aus der Exception-Klasse genutzt werden.
Beides erfordert aber den Zugriff auf die Exception im catch-Zweig eines try-catch-Blocks.

Zur Zeit versuche ich auftretende Exceptions in der main-function und in der überschriebenen
QApplication::notify(..) Funktion zu behandeln.

Code: Alles auswählen

int main (int argc, char* argv[])
{
	QString appName ("appName");
	
	...

	ApplicationEx a (argc, argv, appName);

	AppParams ap (appName, ..);
	MainWindow w (ap);
	w.show();

	a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()));

	string mainName = "* " + appName.toStdString() + " main";
	int retCode;

Application:
	try {
		retCode = a.exec();					/*1*/
	}
	catch (std::exception& e) {
		cout << mainName << endl;
		cout << "exception occurred : " << e.what() << endl;
		goto Application;			// restart application loop
	}
	
	...
	
	catch (...) {
		cout << mainName << endl;
		string s ("unknown exception occurred");
		cout << s << endl;
		goto Application;
	};
    return retCode;
}

Code: Alles auswählen

bool ApplicationEx::notify (QObject* receiver, QEvent* event)
{
	bool errRet = false;
	bool tmp;
	try {
		tmp = QApplication::notify (receiver, event);	/*2*/
	}
	...
	catch (exception& e) {
		cout << " * ApplicationEx::notify :" << endl;
		cout << "exception occurred : " << e.what() << endl;
		return errRet;
	}
	catch (...) {
		...
		string s ("unknown exception occurred");
		clog << " * ApplicationEx::notify : " << s << endl;
		cout << " * ApplicationEx::notify : " << s << endl;
		return errRet;
	};
	return tmp;
}	
Die Kapselung des message-loops /*1*/ machte aber erst in Verbindung mit
dem Überschreiben von QApplication::notify () /*2*/ einen Teil der Exceptions zugänglich.
Aber sowohl bei den Initialisierungen während des Progammstarts als auch beim Beenden
werden Exceptions von Qt-Messages überdeckt.

Somit habe ich - unter anderem - folgende Fragen:

- gibt es in Qt eine bessere Möglichkeit, auf die Exceptions zuzugreifen ?

- kann ich Qt daran hindern, Exceptions in wenig hilfreiche Messageboxes umzuwandeln ?

- Qt besitzt eine Vielzahl von Schaltern, wie QT_NO_STL, QT_NO_REGEXP, .., die an
keiner Stelle der Documentation zu finden waren. Sind darunter auch solche,
die Qt's Umgang mit Fehlermitteilungen steuern.


Vielen Dank im Voraus

bernds

Verfasst: 16. März 2010 14:08
von RHBaum
Was fuer eine Version / Plattform etc verwendest du denn ?

Soeviel ich weiss, ist die qt exceptionneutral.
d.h. sie fasst die exceptions ned an.

Wenn deine exception beim schliessen fliegt, iss das IMHO ned die QT sondern die c++ runtime und zusammenarbeit mit dem BS / entwicklungsumgebung, die die messagebox hochbringen.

z.b. krieg ich auch bei reinen konsolenanwendungen unter windows ne messagebox hoch, wenn ich den den stack mal zerschiesse (mutwillig oder nich).

Also bist du sicher das die qt Exceptions abfaengt ? Laut Doku und styleguide sollte sie das eigentlich nicht tun !

mach mal testweisse nen try catch block um deinen App.exec aufruf und schau ob ob das geworfen wird. Wobei, bei zerschossenen stacks nix mehr garantiert wird :-)

Ciao ...

Verfasst: 17. März 2010 20:00
von bernds
Erstmal danke für Deine Antwort.

Nochmal zu Version und Plattform : Qt 4.4.3 commercial für Windows (XP, SP3) mit Visual Studio 2005.

Wenn man die QApplication::notify (..) Methode überschreibt und den Message-Loop in einem try/catch-Block einschließt (siehe meine Code-Beispiele), fängt Qt sehr wohl Exceptions ab.
Das Problem dabei ist aber, dass eben nicht alle Exceptions von Qt gleich behandelt werden.

Und dass Qt als C++-Framework einen solch elementaren Teil wie die Behandlung von Ausnahmen nur eingeschränkt implementiert, kann ich nicht glauben.

Gruß bernds

Verfasst: 18. März 2010 09:23
von RHBaum
Ehrlich gesagt ich versteh Deine Aussage nicht, bzw. hab Probleme einige deiner Schlussfolgerungen nachzuvollziehen.
Programm.exe - Fehler in der Anwendung
Die Ausnahme "unknown software exception"(0x...) ist ... an der Stelle 0x...
afgetreten. Klicken Sie af "OK", um das Programm zu beenden.
genau die selbe Msg Box seh ich, wenn ich in ner konsolenanwendung Schmutz betreibe, ohne Qt, ohne GUI, reine c++ runtime Anwendung in ner konsole.
Sieht mir also nicht nach einer von QT abgefangenen Exception aus !

unabhaengig von deinem try catch test ....

wenn den stack zerschiesst, z.b. kann ich mir gut vorstellen, das gar keine chance hasst, das als exception zu fangen .... weil du kannst ja im stack gar ned mehr zurueck (der iss ja kaputt), wie solltest dann zu nem uebergeordneten catch kommen ?

Die doofe windows meldung da deutet wiederum darauf hin, das das system von aussen (also windows) mitbekommen hat, das da was schieflaueft. Also scheint es was richtig schwerwiegendes zu sein. Nicht alles kann man über exceptions abfangen ...

Ausserdem, warum steckst du Enrgie rein, den "Fehler" zu vertuschen ???
DU weisst, oder glaubst, das da irgendwas ueber boost serialization geschossen wird, ok. warum versuchst das ned zu richten ? hasst du da gar keine chance ....

Hasst du mal getestet, ob du ueberhaupt ne exception abgefangen bekommst ... ned das irgendwelche doofen compilereinstellungen hasst. Versuchs mal mit ner div durch 0 oder sowas ...

Ciao ...

Verfasst: 18. März 2010 09:40
von franzf
bernds hat geschrieben:Und dass Qt als C++-Framework einen solch elementaren Teil wie die Behandlung von Ausnahmen nur eingeschränkt implementiert, kann ich nicht glauben.
Warum sollte Qt selber Exceptions behandeln? Exceptions sind Ausnahmen, auf die der Programmierer einer Anwendung reagieren muss. Wenn da schon eine Bibliothek ihre Finger rein steckt und Exceptions fängt OHNE sie weiter zu reichen, können richtig schwer zu lösende Probleme auftauchen.

Qt selber meldet bei mir sehr wohl, dass eine Exception aufgetreten ist, lässt die aber einfach durch. Hab das mal getestet, dass ich in meiner Anwendung ne Exception werf.

Code: Alles auswählen

Qt has caught an exception thrown from an event handler. Throwing
exceptions from an event handler is not supported in Qt. You must
reimplement QApplication::notify() and catch all exceptions there.

terminate called after throwing an instance of 'char const*'
Abgebrochen
Wenn dir da jetzt bei deiner eigenen Anwendung die Runtime dazwischefunkt - beschwer dich bei MS :P

Du kannst es auch mal mit neueren Versionen versuchen. Qt-4.6.2 auf nem VS2008. Einfach zum Testen.

N.B.: Ich hab schon öfters gelesen, dass VS2005 ziemlich Probleme mit templates hat. Es kann also sein, dass die Exception nur dort auftritt. Hast du denn keine Möglichkeit, einen aktuellen Compiler zu verwenden?

Verfasst: 26. März 2010 15:43
von Troll.Soft
also ich fahre Qt mit folgenden Einstellungen für QT4.6 und VC2008

Code: Alles auswählen

QT	+= core
QT	+= gui
QT	+= xml
QT	+= svg
QT	+= sql
QT	+= network
QT	+= webkit

CONFIG	+= qt
CONFIG	+= warn_on
CONFIG	+= dll
CONFIG	+= exceptions
CONFIG	+= rtti
CONFIG	+= debug 
man beachte den Eintrag für exceptions.
Damit stelle ich ein, das der Compiler Exceptions für meine Programmteile nutzt. Qt selbst gibt Fehlermeldungen im alten C-Stil zurück.

Dachte bisher auch, das Qt intern keine Exceptions nutzt. Na ja das Denken soll man wohl doch besser den Pferden überlassen. Ein kleiner Scan über 3887 cpp Files von Qt erbrachte 40 Files, die das Makro QT_CATCH nutzen.

hier ist ein Codestück zu diesem Makro aus QComboBox

Code: Alles auswählen

/*!
    Destroys the combobox.
*/
QComboBox::~QComboBox()
{
    // ### check delegateparent and delete delegate if us?
    Q_D(QComboBox);

    QT_TRY {
        disconnect(d->model, SIGNAL(destroyed()),
                this, SLOT(_q_modelDestroyed()));
    } QT_CATCH(...) {
        ; // objects can't throw in destructor
    }
}
und hier noch eins aus qglobal.h

Code: Alles auswählen

#ifdef QT_BOOTSTRAPPED
#  define QT_NO_EXCEPTIONS
#endif
#if !defined(QT_NO_EXCEPTIONS) && defined(Q_CC_GNU) && !defined (__EXCEPTIONS) && !defined(Q_MOC_RUN)
#  define QT_NO_EXCEPTIONS
#endif

#ifdef QT_NO_EXCEPTIONS
#  define QT_TRY if (true)
#  define QT_CATCH(A) else
#  define QT_THROW(A) qt_noop()
#  define QT_RETHROW qt_noop()
#else
#  define QT_TRY try
#  define QT_CATCH(A) catch (A)
#  define QT_THROW(A) throw A
#  define QT_RETHROW throw
#endif
hier noch etwas von QtCore

Code: Alles auswählen


/*!
    Destroys the QCoreApplication object.
*/
QCoreApplication::~QCoreApplication()
{
    qt_call_post_routines();

    self = 0;
    QCoreApplicationPrivate::is_app_closing = true;
    QCoreApplicationPrivate::is_app_running = false;

#if !defined(QT_NO_THREAD)
#if !defined(QT_NO_CONCURRENT)
    // Synchronize and stop the global thread pool threads.
    QThreadPool *globalThreadPool = 0;
    QT_TRY {
        globalThreadPool = QThreadPool::globalInstance();
    } QT_CATCH (...) {
        // swallow the exception, since destructors shouldn't throw
    }
    if (globalThreadPool)
        globalThreadPool->waitForDone();
#endif
    QThread::cleanup();
#endif

    d_func()->threadData->eventDispatcher = 0;
    if (QCoreApplicationPrivate::eventDispatcher)
        QCoreApplicationPrivate::eventDispatcher->closingDown();
    QCoreApplicationPrivate::eventDispatcher = 0;

#ifndef QT_NO_LIBRARY
    delete coreappdata()->app_libpaths;
    coreappdata()->app_libpaths = 0;
#endif
}
also: schalte die Exception im pro-file ein und nutze unbedingt vc2008. Der arbeitet gut mit Qt4.6 zusammen. Den 2005 habe ich damals nach kurzem Test entnervt wieder rausgeschmissen.

tschüß
TrollSoft