Wann sollte ich try-catch-Blöcke einsetzen?



  • Hallo Gemeinschaft,

    ich hoffe es geht euch allen gut! Man macht sich ja so seine Gedanken 😉

    Zur Sache: Ich habe heut' mal wieder ein Grundlagenfrage; Und zwar ist mir mal aufgefallen, dass ich nie mit try-catch-Blöcken arbeite... Als ich mir die Frage stellte warum das so sei, kam ich darauf dass mir garnicht klar ist, wann ich solche Blöcke einsetzen sollte!!!
    Daher meine Fragen: Wann setze ich try-catch-Blöcke ein? Gibt es da so grundlegende Regeln, wann man die verwenden sollte? Oder ist man ein ganz toller Hecht, wenn man die garnicht braucht? 😃

    Bitte lasst mich nicht dumm sterben.

    MfG



  • Ganz einfach. 🙂
    Wenn eine Funktion eine Exception werfen kann und du darauf reagieren möchtest bzw. das Programm sich dann nicht gleich beenden soll, machen einen try/catch-Block.



  • Insbesondere sollte ein Destruktor niemals werfen.



  • Hallo

    Wichtig ist das das gesamte Programm in einem try-catch-Block läuft. Wenn du bei einem VCL-Projekt mal die Hauptdatei mit main-Funktion aufmachst wirst du dort einen try-catch-Block finden in dem eigentlich alle Verarbeitung ausgeführt wird. Dadurch werden erstmal alle Exceptions sauber aufgefangen, das reicht für die meisten einfachen Programme vollkommen aus.
    Erst wenn du innerhalb deines Programms eine Gliederung hast, wo du gerne auch bei schweren Fehlern keinen kompletten Abbruch haben willst, dann solltest du eigene try-catch-Blöcke setzen.
    Zum Beispiel ein Projekt das aus einen Hauptformular besteht, von dem aus ein Unterformular aufgerufen werden kann in dem eine potentiel fehleranfällige Prozedur ausgeführt wird (z.B. verbindung zu einem externen Rechner). In diesem Fall ist es sinnvoll die Prozedur abzusichern.

    void __fastcall TFormMain::ButtonClick(TObject* Sender)
    {
      try
      {
        TFormConnect* form = ...;
        form->ShowModal();
      }
      catch(...)
      {
        ShowMessage("Connection abgebrochen durch Exception!");
      }
    }
    

    bis bald
    akari



  • Danke bis hierhin für eure Antworten.

    Braunstein schrieb:

    Ganz einfach. 🙂
    Wenn eine Funktion eine Exception werfen kann und du darauf reagieren möchtest bzw. das Programm sich dann nicht gleich beenden soll, machen einen try/catch-Block.

    Hmm... für mich als fortgeschrittenen Anfänger kann ja prinzipiell erstmal jede Funktion eine Exception werfen... Wenn ich die jetzt alle mit try-catch versehe ist das Programm ja plötzlich doppelt so groß. Oder anders gesagt: Ich sehe in meinen Programmen nirgendwo die Notwendigkeit try-catch zu benutzen, weil ich nicht sehe wo eine Exception geworfen werden könnte - es funktioniert ja Alles wie es soll!
    Ich tue mich schwer damit zu sagen: "Diese Funktion könnte hier und dort eine Exception werfen.". Das hat sicherlich auch mit Erfahrung zu tun...

    witte schrieb:

    Insbesondere sollte ein Destruktor niemals werfen.

    Als ich ein kleiner Junge war hat unsere Hündin oft geworfen - waren echt drollig die kleinen Dorfmischungen! 🤡 Mal im Ernst: Ich habe gar keine eigenen Destruktoren - mache ich da was falsch?

    akari schrieb:

    Hallo

    Wichtig ist das das gesamte Programm in einem try-catch-Block läuft. Wenn du bei einem VCL-Projekt mal die Hauptdatei mit main-Funktion aufmachst wirst du dort einen try-catch-Block finden in dem eigentlich alle Verarbeitung ausgeführt wird. Dadurch werden erstmal alle Exceptions sauber aufgefangen, das reicht für die meisten einfachen Programme vollkommen aus.

    Ja, dass die Hauptdatei einen try-catch-Block beinhaltet ist mir schonmal aufgefallen. Ok, gut zu wissen, dass das Ausreichen kann! Das würde mich zu dem Schluss führen, dass ich keine try-catch-Blöcke brauche; Wenn ich sie brauchen würde, wäre mir das sicherlich schonmal aufgefallen. Womit ich mich in diesem Zusammenhang allerdings noch zusätzlich schwer tue (Aber das nur am Rande): Wann spricht man von einem einfachen Programm und wann nicht mehr?

    akari schrieb:

    Erst wenn du innerhalb deines Programms eine Gliederung hast, wo du gerne auch bei schweren Fehlern keinen kompletten Abbruch haben willst, dann solltest du eigene try-catch-Blöcke setzen.

    Aber ich versuche doch meine Programme so zu schreiben, dass solche schweren Fehler garnicht erst auftreten können!?!

    akari schrieb:

    Zum Beispiel ein Projekt das aus einen Hauptformular besteht, von dem aus ein Unterformular aufgerufen werden kann in dem eine potentiel fehleranfällige Prozedur ausgeführt wird (z.B. verbindung zu einem externen Rechner). In diesem Fall ist es sinnvoll die Prozedur abzusichern.

    Naja... ich programmiere ja hardwarenah (Gerätesteuerung) und die Kommunikation ist schon fehleranfällig, allerdings wird das über ein Protokoll und TimeOuts geregelt. Die Verbindung ist einfach RS232 oder USB oder Ethernet etc etc.

    Also Alles in Allem komme ich vorerst zu dem Schluss, dass ich im Moment einfach noch keine try-catch-Blöcke brauche!

    MfG

    Edit: Nagut, eigene Destruktoraufrufe habe ich schon in meinen Programmen:

    delete InstanzXY;
    

    zB... Sollte ich diese immer mit try-catch sichern?



  • Hallo

    Kolumbus schrieb:

    akari schrieb:

    Erst wenn du innerhalb deines Programms eine Gliederung hast, wo du gerne auch bei schweren Fehlern keinen kompletten Abbruch haben willst, dann solltest du eigene try-catch-Blöcke setzen.

    Aber ich versuche doch meine Programme so zu schreiben, dass solche schweren Fehler garnicht erst auftreten können!?!

    Das ist ja auch richtig so, aber es wäre leichtsinnig anzunehmen das eine hinreichend große Menge an Quellcode niemals unter keinen Umständen Exceptions werfen wird. Bedenk das Exception "Ausnahmen" bedeuten, also grade für nicht vorhergesehene Probleme gedacht sind, für die es keine Behandlung innerhalb des normalen Programmflußes gibt.
    Hinzu kommt das gerade C++ Bibliotheken Exceptions benutzen. Wenn du zum Beispiel mit der DBE und den Datenbank-komponenten arbeitest wirst du unter Umständen gar nicht umhinkommen dich um Exceptions zu kümmern.
    Solange du aber nur C-Sachen wie WinAPI und Hardware benutzt brauchst du natürlich keine Exception zu erwarten.

    bis bald
    akari



  • Kolumbus schrieb:

    Als ich ein kleiner Junge war hat unsere Hündin oft geworfen - waren echt drollig

    Ich werfe Dir gleich einen Monitor an den Schädel! 🙂
    Was ist wenn Du eine Ausnahme feststellst, eine Konfigurationsdatei soll ausgelesen werden und diese Datei ist nicht vorhanden? Die Klasse die diese Datei auslesen soll weiss doch gar nicht was dann getan werden soll! Das weiss doch nur die darüber liegende Anwendungslogik. Soll abgebrochen werden, soll stattdessen Standardwerte verwendet werden oder soll woanders nach dieser Datei gesucht werden? Dann wirft eben diese Klasse eine Ausnahme und die anfordernde Stelle fängt diesen Fehler und entscheidet was getan werden muss.
    Ein Destruktor benötigst Du wenn Du Ressourcen angefordert hast und diese wieder freigeben musst ohne dass eine Ausnahme diese Freigaben überspringt.



  • Hallo

    Kolumbus schrieb:

    Edit: Nagut, eigene Destruktoraufrufe habe ich schon in meinen Programmen:

    delete InstanzXY;
    

    zB... Sollte ich diese immer mit try-catch sichern?

    Nein. Denn einerseits wurde ja gesagt das Destruktoren keine Exception werfen sollten. Zum anderen stellt sich die Frage ob diese einzelne Zeile wirklich besonders behandelt werden müßte, was meistens bei einem einfachen delete nicht der Fall ist.

    Der Hinweis war eher gedacht wenn du selber einen Destruktor implementierst (und nicht nur einfach ausrufst). Dann solltest du sicherstellen das dein Code keine Exception auslöst.

    bis bald
    akari



  • akari schrieb:

    Erst wenn du innerhalb deines Programms eine Gliederung hast, wo du gerne auch bei schweren Fehlern keinen kompletten Abbruch haben willst, dann solltest du eigene try-catch-Blöcke setzen.
    Zum Beispiel ein Projekt das aus einen Hauptformular besteht, von dem aus ein Unterformular aufgerufen werden kann in dem eine potentiel fehleranfällige Prozedur ausgeführt wird (z.B. verbindung zu einem externen Rechner). In diesem Fall ist es sinnvoll die Prozedur abzusichern.

    void __fastcall TFormMain::ButtonClick(TObject* Sender)
    {
      try
      {
        TFormConnect* form = ...;
        form->ShowModal();
      }
      catch(...)
      {
        ShowMessage("Connection abgebrochen durch Exception!");
      }
    }
    

    Hierzu sei noch angemerkt, daß es in VCL-Programmen einen zweiten universellen Exception-Handler gibt, und zwar im Message-Dispatcher. Jede Event-Funktion wird von diesem aufgerufen; wift sie oder eine Unterfunktion eine Exception, so wird diese gefangen und, sofern sie von der VCL-Klasse Exception abgeleitet ist, mit ShowException() angezeigt. In diesem Beispiel wäre demnach der try-catch-Block überflüssig.

    Dieser Exception-Handler ist recht praktisch; man kann mit TApplicationEvents::OnException z.B. auch selbst zentralisiert Exceptions auswerten.

    Ein großer Nachteil ist, daß der Handler nur Delphi-Exceptions identifizieren kann; wirft man eine C++-Exception, so erhält man die Meldung "External Exception 0xEEFFACE". Es ist allerdings möglich - aber nicht trivial -, den Handler so zu erweitern, daß er auch C++-Exceptions erkennt und korrekt behandelt.



  • audacia schrieb:

    Dieser Exception-Handler ist recht praktisch; man kann mit TApplicationEvents::OnException z.B. auch selbst zentralisiert Exceptions auswerten.

    Ich muss gestehen dass überhaupt kein Freund von diesem Teil bin. OK, ich habe ihn für Notfälle/vergessene try..catch()-Blöcke auch implementiert aber wenn ich alle Probleme zentral behandeln würde würde dieser Fehlerhandler die Hälfte der ganzen App einnehmen, kein Mensch würde da noch durchblicken.



  • Du brauchst deshalb ja nicht gleich alle Exceptions zentralisiert auswerten 😉



  • Ihr seid meine Erklärbären 👍 🙂

    akari schrieb:

    ... Wenn du zum Beispiel mit der DBE und den Datenbank-komponenten arbeitest wirst du unter Umständen gar nicht umhinkommen dich um Exceptions zu kümmern. ...

    Ja, mit Datenbank-Komponenten arbeite ich, ich füge Datensätze in eine Paradox-Tabelle ein - wo muss ich da Exceptions fangen??

    akari schrieb:

    Kolumbus schrieb:

    ... eigene Destruktoraufrufe habe ich schon in meinen Programmen [...] Sollte ich diese immer mit try-catch sichern?

    Nein. [...] Der Hinweis war eher gedacht wenn du selber einen Destruktor implementierst [...]. Dann solltest du sicherstellen das dein Code keine Exception auslöst.

    Ok, verstanden.

    witte schrieb:

    Kolumbus schrieb:

    Als ich ein kleiner Junge war hat unsere Hündin oft geworfen - waren echt drollig die kleinen Dorfmischungen 🤡

    Ich werfe Dir gleich einen Monitor an den Schädel! 🙂

    😮 *DeckungSuch*

    witte schrieb:

    Was ist wenn Du eine Ausnahme feststellst, eine Konfigurationsdatei soll ausgelesen werden und diese Datei ist nicht vorhanden? ...

    Ich prüfe doch vorher mit FindFirst(...), ob die Datei vorhanden ist. :p

    audacia schrieb:

    ... sei noch angemerkt, daß es in VCL-Programmen einen zweiten universellen Exception-Handler gibt, und zwar im Message-Dispatcher. Jede Event-Funktion wird von diesem aufgerufen; wift sie oder eine Unterfunktion eine Exception, so wird diese gefangen und, sofern sie von der VCL-Klasse Exception abgeleitet ist, mit ShowException() angezeigt. In diesem Beispiel wäre demnach der try-catch-Block überflüssig.

    Aha, das ist natürlich praktisch. Den 2. Exception-Handler muss man extra implementieren?

    Ich habe übrigens zufällig grad ein Beispiel in der BCB-Hilfe gefunden, in dem try-catch verwendet wird:

    BCB-Hilfe schrieb:

    BeginUpdate und EndUpdate sollten immer in Verbindung mit einer try...catch-Anweisung verwendet werden, damit EndUpdate sicher aufgerufen wird, falls eine Exception auftritt. Ein Block aus BeginUpdate und EndUpdate hat typischerweise folgende Form:

    void __fastcall TForm1::Button1Click(TObject *Sender)

    {
    ListBox1->Items->BeginUpdate();
    try{
    ListBox1->Items->Clear();
    ListBox1->Items->Add("Irgendetwas");
    ListBox1->Items->Add("Ein paar Daten");
    ListBox1->Items->EndUpdate();
    }
    catch(...){
    ListBox1->Items->EndUpdate(); //wird auch im Fall einer Exception ausgeführt
    throw;
    }
    }

    Das leuchtet erstmal ein, auch wenn ich mir spontan nicht vorstellen kann, warum ->Clear und ->Add nicht funktionieren sollten... Das ist halt mein Problem bei der ganzen Sache - mir fehlt da wohl noch die Erfahrung / Vorstellungskraft!

    MfG



  • Hallo

    Kolumbus schrieb:

    akari schrieb:

    ... Wenn du zum Beispiel mit der DBE und den Datenbank-komponenten arbeitest wirst du unter Umständen gar nicht umhinkommen dich um Exceptions zu kümmern. ...

    Ja, mit Datenbank-Komponenten arbeite ich, ich füge Datensätze in eine Paradox-Tabelle ein - wo muss ich da Exceptions fangen??

    Soweit ich mich erinnern kann wirft zum Beispiel TQuery::ExecSQL eine Exception wenn der SQL-Befehl nicht korrekt ist.

    bis bald
    akari



  • Kolumbus schrieb:

    Ich prüfe doch vorher mit FindFirst(...), ob die Datei vorhanden ist. :p

    Warum nicht mit FileExists? 😉

    Kolumbus schrieb:

    Den 2. Exception-Handler muss man extra implementieren?

    Nein, der ist in jedem VCL-Programm vorhanden. Du kannst das ganz einfach selbst ausprobieren:

    void __fastcall TFrmMain::MyButtonClick (TObject* Sender)
    {
        throw Exception ("Irgendwas lief da schief.");
    }
    

    Kolumbus schrieb:

    Ich habe übrigens zufällig grad ein Beispiel in der BCB-Hilfe gefunden, in dem try-catch verwendet wird:
    <snip>
    Das leuchtet erstmal ein, auch wenn ich mir spontan nicht vorstellen kann, warum ->Clear und ->Add nicht funktionieren sollten...

    Grundsätzlich solltest du immer damit rechnen, daß jede Funktion eine Exception werfen kann. Add dürfte beispielsweise eine werfen, wenn kein Speicherplatz mehr vorhanden ist.
    In Delphi benutzt man für die meisten dieser Fälle ein try/finally-Konstrukt. Das gibt es in C++Builder zwar auch (das Beispiel aus der C++Builder-Hilfe verwendet eine gleichwertige try/catch-Lösung, bei der aber offensichtlich eine gewisse Redundanz auftritt - der EndUpdate()-Aufruf muß zweimal geschrieben werden), doch gewöhnlich benutzt man stattdessen RAII-Wrapper. Anstelle von

    procedure foo;
    var
      sl: TStringList;
    
    begin
      sl := TStringList.Create;
      try
        ...
      finally
        sl.Free;
      end;
    end;
    

    würde man z.B. in C++ so etwas tun:

    void foo (void)
    {
        std::auto_ptr <TStringList> sl (new TStringList);
        ...
    }
    


  • akari schrieb:

    Kolumbus schrieb:

    ... mit Datenbank-Komponenten arbeite ich, ich füge Datensätze in eine Paradox-Tabelle ein - wo muss ich da Exceptions fangen??

    Soweit ich mich erinnern kann wirft zum Beispiel TQuery::ExecSQL eine Exception wenn der SQL-Befehl nicht korrekt ist.

    Ich hab' da eher Befehle ala TTable->InsertRecord()... Mit TQuery hab' ich noch garnicht gearbeitet. Also das Füllen der Paradox-Tabelle läuft über TTable. Aber da gibts bestimmt auch was abzufangen!?

    audacia schrieb:

    Kolumbus schrieb:

    Ich prüfe doch vorher mit FindFirst(...), ob die Datei vorhanden ist. :p

    Warum nicht mit FileExists? 😉

    Ähmm... reine Trainingsmaßnahme am Rande... *rotwerd* Warum einfach, wenn's auch schwierig geht? *duckundweg*
    (Werd's sofort ändern... aber vielleicht erinnere ich mich ja dadurch später mal an FindFirst(...) wenn es nötig ist.)

    audacia schrieb:

    Grundsätzlich solltest du immer damit rechnen, daß jede Funktion eine Exception werfen kann. Add dürfte beispielsweise eine werfen, wenn kein Speicherplatz mehr vorhanden ist....

    Ok, klingt logisch!

    audacia schrieb:

    ... gewöhnlich benutzt man [...] RAII-Wrapper [...]:

    void foo (void)
    {
        std::auto_ptr <TStringList> sl (new TStringList);
        ...
    }
    

    Kannst du das etwas näher beschreiben? Allein das Wort Wrapper zaubert mir eine süße kleine Falte auf die Stirn... 😞

    MfG

    PS: Ich würd' mich ja tierisch gern mal mit einem von euch Profi's zusammensetzen und über mein Programm schauen... Da schlagt ihr bestimmt die Hände über dem Kopf zusammen...



  • Kolumbus schrieb:

    Also das Füllen der Paradox-Tabelle läuft über TTable. Aber da gibts bestimmt auch was abzufangen!?

    Beispielsweise könnte die Anzahl der Elemente in Deinem Record nicht mit der Spaltenanzahl der Tabelle übereinstimmen, DB-Felder zu klein für die Aufnahme von Werten, fehlgeschlagene Typumwandlungen, Eindeutigkeitsverletzungen ...

    audacia schrieb:

    Kolumbus schrieb:

    Ich prüfe doch vorher mit FindFirst(...), ob die Datei vorhanden ist. :p

    Warum nicht mit FileExists? 😉

    Das wird nichts nützen. Beispielsweise könnte die Datei exklusiv geöffnet sein, physische Fehler auf dem Datenträger sein, ungenügende Benutzerrechte, fehlerhafter Dateninhalt und fehlerhafter Struktur... Warum das alles vorher testen? Lass' es doch vom System prüfen und fang' die Ausnahme ab.

    Kolumbus schrieb:

    audacia schrieb:

    ... gewöhnlich benutzt man [...] RAII-Wrapper [...]:

    void foo (void)
    {
        std::auto_ptr <TStringList> sl (new TStringList);
        ...
    }
    

    Kannst du das etwas näher beschreiben? Allein das Wort Wrapper zaubert mir eine süße kleine Falte auf die Stirn... 😞

    Am besten Du beliest Dich zu diesem Thema, RAII, Ausnahmesicherheit und stellst spezifische Fragen. Das ist zuviel um das alles zu erklären.

    Kolumbus schrieb:

    PS: Ich würd' mich ja tierisch gern mal mit einem von euch Profi's zusammensetzen und über mein Programm schauen

    Posten kannst Du den Kram allemal. 🙂



  • witte schrieb:

    Kolumbus schrieb:

    Also das Füllen der Paradox-Tabelle läuft über TTable. Aber da gibts bestimmt auch was abzufangen!?

    Beispielsweise könnte die Anzahl der Elemente in Deinem Record nicht mit der Spaltenanzahl der Tabelle übereinstimmen, DB-Felder zu klein für die Aufnahme von Werten, fehlgeschlagene Typumwandlungen, Eindeutigkeitsverletzungen ...

    audacia schrieb:

    Kolumbus schrieb:

    Ich prüfe doch vorher mit FindFirst(...), ob die Datei vorhanden ist. :p

    Warum nicht mit FileExists? 😉

    Das wird nichts nützen. Beispielsweise könnte die Datei exklusiv geöffnet sein, physische Fehler auf dem Datenträger sein, ungenügende Benutzerrechte, fehlerhafter Dateninhalt und fehlerhafter Struktur...

    Aufhören - da wird einem ja ganz schlecht... Hab's ja verstanden! 😞

    witte schrieb:

    Am besten Du beliest Dich zu diesem Thema, RAII, Ausnahmesicherheit und stellst spezifische Fragen. Das ist zuviel um das alles zu erklären.

    Ok. 🙂

    witte schrieb:

    Kolumbus schrieb:

    PS: Ich würd' mich ja tierisch gern mal mit einem von euch Profi's zusammensetzen und über mein Programm schauen

    Posten kannst Du den Kram allemal. 🙂

    😮 12mal *.cpp mit durchschnittlich je 5 A4-Seiten Code plus Header? Ich glaube nicht, dass das sinnvoll ist...



  • witte schrieb:

    Am besten Du beliest Dich zu diesem Thema, RAII, Ausnahmesicherheit ... Das ist zuviel um das alles zu erklären.

    Habt ihr denn vielleicht mal ein paar gute Links, die das halbwegs verständlich erklären (evtl auch die Anwendung)?
    Ich habe bereits den Wiki-Artikel "Ausnahmebehandlung" gelesen und den dort vorhandenen Link "Programming with Exceptions in C++ O'Reilly Network-Artikel von Kyle Loudon" lese ich gerade..

    Ich habe hier mal eine Event-Methode, die ich gerade geschrieben habe. Wo würdet ihr extra absichern und warum? (Andere Hinweise nehme ich natürlich auch gerne entgegen)

    // Speichern der aktuell angezeigten Daten
    void __fastcall TFormEAShow::BtnSaveClick(TObject *Sender)
    {
    	AnsiString WrkDir= ExtractFilePath(Application->ExeName) + "\EAD";			// Variable mit Arbeitzverzeichnis für Speicherdateien
    	if(!DirectoryExists(WrkDir) && (!CreateDir(WrkDir)))						// wenn Pfad nicht existiert und nicht erstellt werden kann:
    	{ FormMain->Report(102,2,29); return; }										// Fehlermeldung und Abbruch
    	chdir(WrkDir.c_str());														// Arbeitsverzeichnis zum aktuellen Verzeichnis machen
    	TStringList *EADataList= new TStringList;									// StringList-Komponente instanziieren
    	EADataList->Duplicates= dupIgnore;											// StringList-Option: doppelte Einträge ignorieren
    	EADataList->Sorted= false;													// StringList-Option: unsortierte Liste
    	AnsiString DataFile= FormMain->SerNr + ".txt";								// Variable mit Name der Speicherdatei (<Seriennummer>.txt)
    	if(FileExists(DataFile))													// wenn Datei existiert:
    	{
    		EADataList->LoadFromFile(DataFile);										// Dateiinhalt in die StringList-Instanz laden
    //V		EADataList->Clear();													// geladenen Text löschen (bei Bedarf)
    	}
    	else EADataList->Append("Hinweis: Wählen Sie zur Anzeige der Datei eine \
    nicht-proportionale Schriftart (zB. Courier / Courier New)! \r\n");				// wenn neue Datei: Hinweis am Dateianfang
    	EADataList->Append("\r\n ============================================== ");	// Kopfzeilen des neuen Dateieintrags in die StringList...
    	EADataList->Append(" Echtzeit-Messdaten vom: " + DateTimeToStr(Now()));		// ...
    	EADataList->Append(" ============================================== ");		// ...
    	short Idx, EntryCount= 0;													// Variablen für Dateieinträge (Schleifen- und Eintragzähler)...
    	AnsiString Entry[10], TmpStr;												// ...(Array mit Einträgen und Eintrag temporär (für Formatierung))
    	for(Idx= 1; Idx < ComponentCount; Idx++)									// Loop: alle Formkomponenten durchlaufen
    	{
    		if(TPanel *vPnl= dynamic_cast<TPanel*>(Components[Idx]))				// wenn aktuelle Kompo als Panel gecastet werden kann:
    		{
    			if((0 < vPnl->Tag) && (vPnl->Tag < 11) && (vPnl->Caption != "."))	// wenn Tag des Panel im Bereich 1..10 und Panel nicht ungenutzt:
    			{
    //U				Entry[vPnl->Tag-1].Insert(vPnl->Caption + ":   ", 1);			// unformatierte Version
    				TmpStr= IntToStr(vPnl->Tag) + "\t- " + vPnl->Caption + ":\t";	// Messwertnummer und -name (aus Panel-Tag und -Caption) in temporären Eintrag
    				if(vPnl->Tag < 10) TmpStr.Insert(" ", 1);						// bei einstelligen Nummern, 1 Leerzeichen am Anfang einfügen
    				if(vPnl->Caption.Length() <= 12)								// wenn Messwert-Bezeichnung kürzer als 13 Zeichen:
    					TmpStr.Insert("\t", TmpStr.Pos(":")+1);						// nach ":" Tab einfügen => Spalten in *.txt bei nicht-proportionaler Schrift (zB. Courier)
    				Entry[vPnl->Tag-1].Insert(TmpStr, 1);							// temporären Eintrag in Array mit Einträgen
    				EntryCount++;													// Eintragzähler inkrementieren
    			}
    			else
    				if((10 < vPnl->Tag < 21) && (vPnl->Caption != "."))				// wenn Tag des Panel im Bereich 11..20 und Panel nicht ungenutzt:
    				{
    //U					Entry[vPnl->Tag-11]+= vPnl->Caption;						// unformatierte Version
    					TmpStr= vPnl->Caption;										// Messwert und Einheit in temporären Eintrag
    					if(TmpStr.IsDelimiter("0123456789", 1))						// wenn das 1. Zeichen eine Zahl ist (Feldrichtung ausschliessen):
    						while(TmpStr.LastDelimiter("0123456789") < 6)			// Zahlenwerte ausrichten...
    							TmpStr.Insert(" ", 1);								// ...
    					Entry[vPnl->Tag-11]+= TmpStr;								// temp. Eintrag in Array
    				}
    		}
    	}
    	for(Idx= 0; Idx < EntryCount; Idx++)										// Loop: im Array eingetragene Einträge durchlaufen
    	{	EADataList->Append("\r\n" + Entry[Idx]);	}							// Leerzeile und Eintrag aus Array in StringList
    	EADataList->SaveToFile(DataFile);											// StringList-Inhalt in Datei speichern
    	delete EADataList;															// StringList-Instanz freigeben
    }
    //----------------------------------------------------------------------------
    

    MfG



  • Hallo

    Absicherungswürdig sind zunächst alle Instanzen die du mit new anlegst und am Ende wieder mit delete löscht, in deinem Fall EADataList. Denn sollte während der Bearbeitung eine Exception auftreten, wird die Funktion vor dem delete verlassen.
    Und wie du das absichern kannst hat ja witte mit dem std::auto_ptr schon gezeigt.

    bis bald
    akari



  • Exceptions sind schon alleine dafür ganz praktisch, um die Stelle festzustellen, an der ein Fehler aufgetreten ist. Ist gibt nichts schöneres als eine Exception mit einer nichtssagenden Fehlermeldung, die ganz nach oben durchgerasselt ist. Dann heißt es: viel Spaß beim Suchen.


Anmelden zum Antworten