Ein Schlechtes Exception Beispiel
StartSeite | Neues | TestSeite | ForumSeite | Teilnehmer | Kategorien | Index | Hilfe | Einstellungen | Ändern
Hier ein paar echte (leicht vereinfachte) Beispiele aus C++, wo Exceptions falsch gebraucht werden. Dies sind nicht irgenwelche erfundene Beispiele, alle wurden in der freien Natur gesichtet:
Exceptions statt Bedingung | |
In MS-Visual C++ können Access Violations als Exceptions behandelt werden. Naive Programmierer versuchen dann folgendes:
| try {
strCaption = "Enter Data for " + pContract->GetCustomer()->GetName();
} catch(...) {
strCaption = "Enter Data for new Customer";
} |
|
|
Hier soll der catch-Block dafür sorgen, dass die Access Violation, die auftritt, wenn GetCustomer() NULL liefert, abgefangen wird. Leider werden dadurch auch alle anderen Exceptions die da auftreten können versteckt.
Richtiger wäre:
| Customer *pCustomer = 0;
if (0 != pContract && 0 != (pCustomer = pContract->GetCustomer())) {
strCaption = "Enter Data for " + pCustomer->GetName();
} else {
strCaption = "Enter Data for new Customer";
} |
|
|
Dies ist aber noch lange kein guter Code, denn er verletzt das Gesetz von Demeter, also wäre weiteres Refactoring angesagt. Aber zumindest ist hier das gefährliche catch(...) beseitigt.
Exceptions vergessen | |
In C++ wird man nicht gezwungen, Exceptions zu deklarieren (ähnlich wie in Java RuntimeException?).
| ++m_nDepth;
Iterator *pI = col->CreateIterator(); // ruft new() auf
while (!pI->Done()) {
// mach was mit dem Objekt pI->GetItem();
pI->Next();
}
delete pI;
--m_nDepth; |
|
|
Wird in der while Schleife eine Exception geworfen, haben wird der Iterator nicht mehr dealloziert und m_nDepth wird nicht dekrementiert, Memory- und Ressourcenlecks sind die Folge. Um sicher aufzuräumen kann man in Java mit finally, in C++ mit Destruktoren arbeiten. Hier eine exceptionssichere Version:
| Inkrementor incDepth(m_nDepth);
AutoPtr<Iterator> pI = col->CreateIterator(); // ruft new() auf
while (!pI->Done()) {
// mach was mit dem Objekt pI->GetItem();
pI->Next();
}
// delete pI nicht nötig, der Destruktor von AutoPtr kümmert sich darum
// --m_nDepth nicht nötig, der Destruktor von Inkrementor kümmert sich darum |
|
|
Das ist natürlich auch noch nicht schön. Warum muss man pI löschen obwohl nirgends new aufgerufen wurde?
Iterator ist eine abstrakte Klasse, man könnte sie daher erweitern:
| class Iterator {
private:
InternalIterator *m_pI;
public:
Iterator(Collection const& con) {
m_pI = con.CreateIterator();
}
~Iterator() {
delete m_pI;
}
...
}
...
Inkrementor incDepth(m_nDepth);
Iterator i(col);
while (!i.Done()) {
// mach was mit dem Objekt pI->GetItem();
i.Next();
}
// --m_nDepth nicht nötig, der Destruktor von Inkrementor kümmert sich darum |
|
|
Siehe auch: EinGutesExceptionBeispiel ExceptionDiskussion ExceptionsDiskussion
KategorieProgrammierung KategorieException
StartSeite | Neues | TestSeite | ForumSeite | Teilnehmer | Kategorien | Index | Hilfe | Einstellungen | Ändern
Text dieser Seite ändern (zuletzt geändert: 21. Januar 2004 19:58 (diff))