welche vorteile bietet c++ gegenüber c
-
Decimad schrieb:
Nunja, für das, was dort einen Absturz gab, würde ich ehrlich gesagt keine Exceptions verwenden, sondern den Quelltext robuster/fehlerfreier machen. Ich hab für mich nach Jahren gedanklich immer noch keinen goldenen Punkt gefunden, ab dem ich anerkenne, dass ein behandelbarer Fehler einer Exception würdig ist.
Wenn die GDI-Ressourcen aufgebraucht sind, kann man abstürzen lassen (also typische C-Fehlerbehandlung, nämlich gar keine), oder man kann mit exit() raus (also nicht das Dokument abspeichern, naja, wenigstens keine korrupten Daten). Oder viel viel Arbeit reinstecken. Viel.
Oder man nimmt C++.
Zuverlässige Destruktoren sind für mich der Grund, weshalb ich lieber in Perl schreibe als in PHP.
-
Eisflamme schrieb:
Und dass man schneller zu einem Ergebnis kommt, liegt wohl auch einfach nur darin begründet, dass man in C weniger Konzepte verstehen muss.
Ja, aber viele moderne C++ Experten verstehen ja nichtmal diese grundlegenden
(prozeduralen) Konzepte, weil sie von den 'modernen' Lehrbüchern sofort ins
kalte C++ Wasser geworfen werden, wo der Tanz (OOP, Templates) vor dem
aufrechten Gang (Schleifen, Funktionen) gelehrt wird, also kurzerhand jene
Teilmenge von C++, die über C hinaus geht, falscher Weise zuerst durchgenommen
wird. Braucht man ja nur ins C++ Unterforum gucken, wo die Leute zwar brav
mit <vector>, <boost> usw. arbeiten, aber so ihre liebe Not mit dem Vertauschen
von Variablenwerten oder dem Finden einzelner Zeichen in einem String
haben, also wo die elementarsten Operationen zum Problem werden.
Also mich wundert's angesichts dieses Umstands kaum, dass moderne C++ Software
typischer Weise erst nach dem 1000. Bugfix halbwegs das tut, was sie soll:
Weil die Entwickler ja oft C++ vor (und nicht selten sogar anstelle)
des eigentlichen Programmierens (aka algorithmisches Denken)
gelernt haben.@volkard
Mein Freund ist mittlerweile dazu übergegangen, mehrere Funktionen meiner
C-Engine für seine C++ Engine zu wrappen und auf dieser Basis weiter zu
arbeiten (was übrigens sowieso die typische Vorgangsweise in C++ zu sein
scheint: Bereits existierende, gut implementierte C-Funktionen/Module neu zu
'verkleiden' und das Resultat dann als coole C++ Lösung zu bezeichnen.
Das fängt schon alleine damit an, dass man sich dutzende neue Namen für
den elementaren Zuweisungsoperator ausdenkt:
Klassen-Getter() und Setter() - und sich dann einredet, man hätte ebenso viele Funktionen 'neu' erfunden, wie man Getter und Setter hat.
Was für eine Errungenschaft! Diese coole Kapselung von Klassen-Members ist
ja schon ein Beispiel für die generelle C++ Tendenz, die elementarsten Räder
auf zigfache Weise immer wieder auf's neue zu erfinden, neu zu benennen, und
insgesamt nicht recht viel mehr zuwege zu bringen als sich neue Namen für
allerlei - bereits existierende - Funktionen auszudenken.
Die sinnvolle Kombination elementarer Operationen (Zuweisung z.B.)
zu zunehmend komplexeren Prozeduren und Funktionen ist ja veraltet und hat
in C++ nix verloren, hehe. Dazu wird's wohl noch für geraume Zeit so naive
C-Arbeiter geben müssen, damit die C++ Leutchen was haben, das sie in ihre
Klassen verpacken können.
mfg
-
Inwiefern vereinfacht mir denn nun eine Exception das Freilassen aller nicht zwingend benötigten (Beispielsweise Caches) GDI-Ressourcen um es nochmal zu probieren? Hast du da irgendwo ein Produktiv-Beispiel? Vielleicht erkenne ich dann ja die mir verborgene Simplizität und Eleganz! Am besten natürlich eine Gegenüberstellung, die anschließend generalisiert wird, natürlich.
-
freigeist3 schrieb:
Eisflamme schrieb:
Und dass man schneller zu einem Ergebnis kommt, liegt wohl auch einfach nur darin begründet, dass man in C weniger Konzepte verstehen muss.
Ja, aber viele moderne C++ Experten verstehen ja nichtmal diese grundlegenden
(prozeduralen) Konzepte, weil sie von den 'modernen' Lehrbüchern sofort ins
kalte C++ Wasser geworfen werden, wo der Tanz (OOP, Templates) vor dem
aufrechten Gang (Schleifen, Funktionen) gelehrt wird, also kurzerhand jene
Teilmenge von C++, die über C hinaus geht, falscher Weise zuerst durchgenommen
wird. Braucht man ja nur ins C++ Unterforum gucken, wo die Leute zwar brav
mit <vector>, <boost> usw. arbeiten, aber so ihre liebe Not mit dem Vertauschen
von Variablenwerten oder dem Finden einzelner Zeichen in einem String
haben, also wo die elementarsten Operationen zum Problem werden.
Also mich wundert's angesichts dieses Umstands kaum, dass moderne C++ Software
typischer Weise erst nach dem 1000. Bugfix halbwegs das tut, was sie soll:
Weil die Entwickler ja oft C++ vor (und nicht selten sogar anstelle)
des eigentlichen Programmierens (aka algorithmisches Denken)
gelernt haben.@volkard
Mein Freund ist mittlerweile dazu übergegangen, mehrere Funktionen meiner
C-Engine für seine C++ Engine zu wrappen und auf dieser Basis weiter zu
arbeiten (was übrigens sowieso die typische Vorgangsweise in C++ zu sein
scheint: Bereits existierende, gut implementierte C-Funktionen/Module neu zu
'verkleiden' und das Resultat dann als coole C++ Lösung zu bezeichnen.
Das fängt schon alleine damit an, dass man sich dutzende neue Namen für
den elementaren Zuweisungsoperator ausdenkt:
Klassen-Getter() und Setter() - und sich dann einredet, man hätte ebenso viele Funktionen 'neu' erfunden, wie man Getter und Setter hat.
Was für eine Errungenschaft! Diese coole Kapselung von Klassen-Members ist
ja schon ein Beispiel für die generelle C++ Tendenz, die elementarsten Räder
auf zigfache Weise immer wieder auf's neue zu erfinden, neu zu benennen, und
insgesamt nicht recht viel mehr zuwege zu bringen als sich neue Namen für
allerlei - bereits existierende - Funktionen auszudenken.
Die sinnvolle Kombination elementarer Operationen (Zuweisung z.B.)
zu zunehmend komplexeren Prozeduren und Funktionen ist ja veraltet und hat
in C++ nix verloren, hehe. Dazu wird's wohl noch für geraume Zeit so naive
C-Arbeiter geben müssen, damit die C++ Leutchen was haben, das sie in ihre
Klassen verpacken können.
mfgSoviel Ahnung vom Programmieren wie Du hatte ich nach sechs Wochen. Du bist einfach noch nicht so weit, mitzureden.
-
Du
Mein Freund ist mittlerweile dazu übergegangen, mehrere Funktionen meiner
C-Engine für seine C++ Engine zu wrappen und auf dieser Basis weiter zu
arbeiten (was übrigens sowieso die typische Vorgangsweise in C++ zu sein
scheint: Bereits existierende, gut implementierte C-Funktionen/Module neu zu
'verkleiden' und das Resultat dann als coole C++ Lösung zu bezeichnen.bist
Das fängt schon alleine damit an, dass man sich dutzende neue Namen für
den elementaren Zuweisungsoperator ausdenkt:
Klassen-Getter() und Setter() - und sich dann einredet, man hätte ebenso viele Funktionen 'neu' erfunden, wie man Getter und Setter hat.
Was für eine Errungenschaft!so was von
Diese coole Kapselung von Klassen-Members ist
ja schon ein Beispiel für die generelle C++ Tendenz, die elementarsten Räder
auf zigfache Weise immer wieder auf's neue zu erfinden, neu zu benennen, und
insgesamt nicht recht viel mehr zuwege zu bringen als sich neue Namen für
allerlei - bereits existierende - Funktionen auszudenken.raus.
-
Decimad schrieb:
Inwiefern vereinfacht mir denn nun eine Exception das Freilassen aller nicht zwingend benötigten (Beispielsweise Caches) GDI-Ressourcen um es nochmal zu probieren?
Beim Stack-Unwinding werden Destruktoren aufgerufen. Wenn Du dem Catcher sagen willst, er soll es in ein paar Sekunden nochmal probieren, kannste ihm auch sagen, daß er Caches löschen soll.
Aber mir hätte es schon gereicht, die Daten ohne weitere Anzeige zu speichern, eventuelle Datenbankverbindungen zu schließen, Datei-Locks freizugeben, den Video-Modus zurückzusetzen, Netzwerkverbindungen zu trennen, ganz einfache Sachen, die ganz lästig sind, wenn man sie nicht macht.
-
Das Guttenberg unter den Programmen sozusagen, der geordnete Abgang! Nee, das sehe ich 1:1 ein, das ist okay. Ob man mit der GDI Probleme bekommt, oder dem Speicher, liegt ja auch bei fehlerfreiem Programmablauf oft nicht in der eigenen Hand. Aber diese ganzen DivisionByZero-Exceptions in den Algorithmen usw. kann ich eben nicht so ganz nachvollziehen.
-
volkard schrieb:
Decimad schrieb:
Inwiefern vereinfacht mir denn nun eine Exception das Freilassen aller nicht zwingend benötigten (Beispielsweise Caches) GDI-Ressourcen um es nochmal zu probieren?
Beim Stack-Unwinding werden Destruktoren aufgerufen.
Hmm, sind das nicht die Destuktoren, die selbst keine Exceptions werfen sollten? Weil wenn Sie das tun, undefiniertes Verhalten auftritt bzw. die Desktruktion einer Objekthierarchie kaputt geht? Also wäre es eigentlich sinnvoll eine "public: void ReleaseResources()"-Methode zu machen, damit man im Fall einer Exception beim Freigeben von Ressourcen noch handeln kann. Wer ruft die optimalerweise auf? Der Destruktor der Klasse? Der müsste dann die Exception schlucken, wenn er sie nicht behandeln kann. Unschön. Oder doch Clientcode? Dann geben wir das Schicksal in externe Hände.
-
Decimad schrieb:
Aber diese ganzen DivisionByZero-Exceptions in den Algorithmen usw. kann ich eben nicht so ganz nachvollziehen.
Viele libs werfen grotesk viele Exceptions. Das kann man in Java machen. In C++ sollte man sie sparsam einsetzen.
Zum Beispiel eineEmptyStackException wäre in Java Katastrophe.Eine DivisionByZero kann Sinn ergeben, zum Beispiel wenn der Matrizeninvertierer mitten im Rechnen feststllt, daß sie nicht invertierbar war. Ich könnte auch stur weiterrechnen, aber dann müßte ich nachher nochmal über die ganze Matrix laufen und schauen, daß nirgend NAN oder INF aufgetaucht ist.
Oder die Invertierfunktion gibt irgendwie anders zurück, ob's geklappt hat. Zusätzlicher Parameter oder zwei Rückgaben? Nicht hübsch. Das Matrixformat ändern, daß sie auch sowas wie NAN darstellen kann. Hmm, wenn es angemessen ist, mag es einen Versuch wert sein. Aber hier tendiere ich eher zu Exception, klingt einfach schneller als überall mit if zu hantieren und zu prüfen. Und in Zusammenhängen, wo es fast immer klappt, kann ich hübsch die Füße hochlegen und nur in der main() fangen, und trotzdem geht mir kein Rechenfehler durch die Lappen.
-
Ich versteh gerade nicht, wieso irgend ein dtor sowieso eine Exception werfen können sollte. Das würde ich aus der Problematik heraus gar nicht erst erlauben. Wenn irgendwas nicht gelöscht werden kann, dann ist das eben Pech und wird evtl. noch irgendwo reingeschrieben (und wenn die entsprechende Datei nicht geöffnet wird, dann eben auch da nicht). Wenn ein dtor seinen Speicher nicht freigeben kann, wie will man so etwas denn sinnvoll behandeln? Das kann dann ja die Runtime bzw. das BS übernehmen...
Darf im Stack-Unwinding-Prozess eigentlich auch keine Ausnahme lokal erzeugt und gefangen werden? Sodass im dtor try{bla}catch(...){} steht? Dafür sähe ich gewisse Anwendung, wenn so was eben Mal passieren kann. Oder geht das auch nicht?
-
GPC schrieb:
Hmm, sind das nicht die Destuktoren, die selbst keine Exceptions werfen sollten?
Das sind die Fälle, wo meine Programme fehlerhaft sind. Also Platte zu 100% voll => es wird bei kritischem Fehler nicht mehr korrekt gespeichert UND der Benutzer sieht es nicht. Er würde keine Messagebox bekommen, wenn die Datenbankverbindung oder andere Netzwerkverbindung nicht geschlossen werden könnte oder der Videomodus nicht zurückgesetzt werden könnte. Das hat mich noch nicht genervt.
GPC schrieb:
void ReleaseResources()
Nein, die heilt gar nichts.
GPC schrieb:
Oder doch Clientcode? Dann geben wir das Schicksal in externe Hände.
Ich weiß nicht, was hiermit gemeint ist.
-
volkard schrieb:
GPC schrieb:
Hmm, sind das nicht die Destuktoren, die selbst keine Exceptions werfen sollten?
Das sind die Fälle, wo meine Programme fehlerhaft sind. Also Platte zu 100% voll => es wird bei kritischem Fehler nicht mehr korrekt gespeichert UND der Benutzer sieht es nicht. Er würde keine Messagebox bekommen, wenn die Datenbankverbindung oder andere Netzwerkverbindung nicht geschlossen werden könnte oder der Videomodus nicht zurückgesetzt werden könnte. Das hat mich noch nicht genervt.
Im Endeffekt heißt das einfach, dass dann halt business as usual gemacht wird, wenn der Destruktor Ressourcen nicht korrekt freigeben konnte?
Bzw. sich das Problem dahingehend ausdehnt, dass man in Destruktoren keine Funktionen aufrufen sollte, die eine Exception werfen könnte.GPC schrieb:
void ReleaseResources()
Nein, die heilt gar nichts.
Offensichtlich kann man sich auf Destruktoren aber auch nicht verlassen.
GPC schrieb:
Oder doch Clientcode? Dann geben wir das Schicksal in externe Hände.
Ich weiß nicht, was hiermit gemeint ist.
Dass der Code, der deine Klasse benutzt, dafür verantwortlich ist, dass auch Exceptions in solchen Release-Methoden gehandelt wird, da der Destruktor es nicht kann.
Durch das Stack-Unwinding geht btw. auch der Call stack verloren
-
GPC schrieb:
Im Endeffekt heißt das einfach, dass dann halt business as usual gemacht wird, wenn der Destruktor Ressourcen nicht korrekt freigeben konnte?
Bzw. sich das Problem dahingehend ausdehnt, dass man in Destruktoren keine Funktionen aufrufen sollte, die eine Exception werfen könnte.Ja.
-
GPC schrieb:
Im Endeffekt heißt das einfach, dass dann halt business as usual gemacht wird, wenn der Destruktor Ressourcen nicht korrekt freigeben konnte?
Bzw. sich das Problem dahingehend ausdehnt, dass man in Destruktoren keine Funktionen aufrufen sollte, die eine Exception werfen könnte.Im Destruktor selbst kann man durchaus Funktionen aufrufen, die Exceptions werfen, diese sollten aber noch im Destruktor abgefangen werden. Wobei es noch immer die Möglichkeit gibt, das ganze in einem Logfile zu protokollieren (wenn möglich).
-
Im Endeffekt heißt das einfach, dass dann halt business as usual gemacht wird, wenn der Destruktor Ressourcen nicht korrekt freigeben konnte?
Bzw. sich das Problem dahingehend ausdehnt, dass man in Destruktoren keine Funktionen aufrufen sollte, die eine Exception werfen könnte.Was willst du denn jetzt damit überhaupt sagen?
Wenn tatsächlich die im Konstruktor angeforderten Ressourcen nicht mehr freigegeben werden können, hat man sowieso ein ziemlich großes Problem, das nicht vom Programm abgefangen werden kann.
Könntest du ein Beispiel geben, bei dem das relevant wäre?
-
Aber mal eine andere Frage, wer garantiert einem eigentlich, dass durch das Zerstören und das Stackunwinding nicht eventuell noch viel größerer Schaden angerichtet wird, wenn dort als Folgefehler noch etwas katastrophales passiert?^^ Zumeist muss man sich die Fälle, in denen das auftritt sowieso erstmal künstlich theoretisch konstruieren, und um da einen schlüssigen Beweis für die Überlegenheit zu finden, muss man das wahrscheinlich sogar noch gründlich tun!
-
dass durch das Zerstören und das Stackunwinding nicht eventuell noch viel größerer Schaden angerichtet wird, wenn dort als Folgefehler noch etwas katastrophales passiert?^^
Was denn für Folgefehler? Solange Destruktoren nicht werfen, gibt es auch keine Folgefehler.
-
Decimad schrieb:
Aber mal eine andere Frage, wer garantiert einem eigentlich, dass durch das Zerstören und das Stackunwinding nicht eventuell noch viel größerer Schaden angerichtet wird, wenn dort als Folgefehler noch etwas katastrophales passiert?^^
Keiner. Aber ich kann mir gerade nicht vorstellen, wie man eine Katastrophe dadurch herbeiführen könnte (außer mal system("echo j|format e: /V:haha") an passende Stelle zu schreiben.)
-
Das erschließt sich mir jetzt noch nicht so ganz irgendwie... (Gemeint ist hier nicht etwa irgendwer, sondern Irgendwer! ...ich sollte öfter zitieren!)
-
Decimad schrieb:
Aber mal eine andere Frage, wer garantiert einem eigentlich, dass durch das Zerstören und das Stackunwinding nicht eventuell noch viel größerer Schaden angerichtet wird, wenn dort als Folgefehler noch etwas katastrophales passiert?^^ Zumeist muss man sich die Fälle, in denen das auftritt sowieso erstmal künstlich theoretisch konstruieren, und um da einen schlüssigen Beweis für die Überlegenheit zu finden, muss man das wahrscheinlich sogar noch gründlich tun!
Wer garantiert, dass ein Funktionsaufruf fehlerfrei verläuft? Oder eine Zuweisung? Das sind Fehler die das Programm selbst nicht behandeln kann. Und wenn selbst solche einfachen Operationen scheitern ist das Programm (evt. sogar das Betriebssystem) zum Absturz verurteilt ^^.