Exception
-
Warum fangt ihr const? Wenn ich ne Exception weiterwerfe, will ich ihr meistens weitere Informationen mit auf den Weg geben.
-
Michael E. schrieb:
Warum fangt ihr const? Wenn ich ne Exception weiterwerfe, will ich ihr meistens weitere Informationen mit auf den Weg geben.
Klar möchte ich auch weitere Informationen, allerdings (i. d. R.) nur
Informationen und keine Sachen, die das Objekt verändern.Wenn du natürlich in der Exception nen Counter hast, wie oft sie
schon weitergeworfen wurde und den erhöhst, brauchst du eine non-const ReferenzGegenfrage: Wann verwendest du const-Referenzen?
-
CSpille schrieb:
Michael E. schrieb:
Warum fangt ihr const? Wenn ich ne Exception weiterwerfe, will ich ihr meistens weitere Informationen mit auf den Weg geben.
Klar möchte ich auch weitere Informationen, allerdings (i. d. R.) nur
Informationen und keine Sachen, die das Objekt verändern.Versteh ich nicht. Wenn ich dieselbe Exception weiterwerfen will (also ein pures "throw;" schreiben will) un dieser Exception weitere Informationen geben will, muss ich sie auch verändern.
Gegenfrage: Wann verwendest du const-Referenzen?
Nie, weil ich keinen Sinn darin sehe. Ich bekomm eh ne Kopie übergeben.
-
Michael E. schrieb:
CSpille schrieb:
Michael E. schrieb:
Warum fangt ihr const? Wenn ich ne Exception weiterwerfe, will ich ihr meistens weitere Informationen mit auf den Weg geben.
Klar möchte ich auch weitere Informationen, allerdings (i. d. R.) nur
Informationen und keine Sachen, die das Objekt verändern.Versteh ich nicht. Wenn ich dieselbe Exception weiterwerfen will (also ein pures "throw;" schreiben will) un dieser Exception weitere Informationen geben will, muss ich sie auch verändern.
Korrekt! Aber veränderst du das Objekt in der Regel wirklich?
Schreibst du weitere Infos in das Objekt oder veränderst vorhandene?
Du holst dir meistens die Fehlermeldung und einen Error-Code
oder kuckst dir evtl. noch andere Daten an.
Ein Weiterwerfen ist wohl keine Veränderung des Objektes.
und wenn mir das 'const' bei einer Fehleranalyse nur sagt:
"Don't worry, I won't change your object in this catch-block"
ist es für mich genug ein 'const' davor zu schreibenMichael E. schrieb:
Gegenfrage: Wann verwendest du const-Referenzen?
Nie, weil ich keinen Sinn darin sehe. Ich bekomm eh ne Kopie übergeben.
Über diese Antwort bin ich etwas erstaunt, zumal sie von einem Benutzer mit
3500 Beiträgen kommt.
Ich rede von const-Referenzen im Allgemeinen, nicht im Zusammenhang mit Exceptions.
Ich vermute das führte dich zu deiner Aussage 'Nie', oder?Als Beispiel, dass du keine Kopie kriegst:
#include<iostream> class MyException{ public: int i; MyException(){i=0;} MyException(const MyException& e){ std::cout << "create copy" << std::endl; } }; int main() { try{ try { // MyException e; // e.i=0; // throw e; throw MyException(); } catch( MyException& exc ) { std::cout << exc.i << std::endl; exc.i = 1; throw; } }catch(MyException& exc){ std::cout << exc.i << std::endl; } return 0; }0 1Du kriegst (evtl.) eine Kopie von der Original-Exception,
aber diese wird gemacht um das Objekt an einen sicheren Ort zu transferierenEDIT: Das Objekt wird (bei meinem Compiler) zum Beispiel kopiert, wenn du
die auskommentierte Version verwendest.
EDIT2: Ich hab keine Ahnung, ob es beim Weiterschmeißen eine Garantie gibt,
dass das Objekt nicht kopiert wird, jedoch sollte eine Kopie auch die veränderten
Daten enthalten.Gruß,
CSpille
-
CSpille schrieb:
Korrekt! Aber veränderst du das Objekt in der Regel wirklich?
Manchmal.
und wenn mir das 'const' bei einer Fehleranalyse nur sagt:
"Don't worry, I won't change your object in this catch-block"
ist es für mich genug ein 'const' davor zu schreibenWem genau sagst du, dass sein Objekt nicht verändert wird? Es gibt nur zwei Fälle:
- Du wirfst ein Objekt, das schon vorher existiert hat. Dann wird garantiert eine Kopie beim ersten Werfen erstellt, sodass sich das Originalobjekt nicht ändern kann.
- Ich erstelle extra ein Objekt, das ich dann durch die Gegend werfe.
So oder so habe ich also in einem Catch-Block ein Objekt, das nur in Catch-Blöcken leben kann, es hat weder vor dem ersten Wurf gelebt, noch nach dem letzten Fangen. Nun ist es bei Catch-Blöcken so, dass ich nicht weitere Catch-Blöcke aufrufe wie man das bei normalen Funktionen macht, sondern ein "Aufruf" eines anderen Catch-Blocks bedeutet automatisch, dass der aufrufende Catchblock verlassen wird. Also bekommt der Aufrufer das Objekt nie mehr zu sehen, weshalb er sich nicht mehr für Veränderungen am Objekt interessieren kann. Welchen Sinn sollte dann also ein const haben?
Ich vermute das führte dich zu deiner Aussage 'Nie', oder?
Ja, ich rede nur vom const beim Fangen von Exceptions.
Als Beispiel, dass du keine Kopie kriegst:
Das ist klar.
EDIT2: Ich hab keine Ahnung, ob es beim Weiterschmeißen eine Garantie gibt,
dass das Objekt nicht kopiert wirdGenau dafür wurde "throw;" erfunden. Es wird garantiert dasselbe Objekt weitergeworfen.
Edit: Zweideutiges "Wem sagst du das denn?" rausgenommen.
-
Michael E. schrieb:
So oder so habe ich also in einem Catch-Block ein Objekt, das nur in Catch-Blöcken leben kann, es hat weder vor dem ersten Wurf gelebt, noch nach dem letzten Fangen. Nun ist es bei Catch-Blöcken so, dass ich nicht weitere Catch-Blöcke aufrufe wie man das bei normalen Funktionen macht, sondern ein "Aufruf" eines anderen Catch-Blocks bedeutet automatisch, dass der aufrufende Catchblock verlassen wird. Also bekommt der Aufrufer das Objekt nie mehr zu sehen, weshalb er sich nicht mehr für Veränderungen am Objekt interessieren kann. Welchen Sinn sollte dann also ein const haben?
Kuck nochmal auf mein Beispiel.
Im Fall dass ich die Exception weiterwerfe, interessiert mich die Änderung
im nächsten catch-Block...Außerdem kannst du ja (theoretisch - praktisch eher selten) einen Verweis
auf irgendein länger lebendes Heap-Objekt in deiner Exception haben.
Ohne const, könnstest du auf dieses Objekt ja auch schreibenden Zugriff erlangen.
Die Änderung dieses Objektes wird dich in deinem späteren Programmverlauf sicher
interessieren...
-
CSpille schrieb:
Kuck nochmal auf mein Beispiel.
Im Fall dass ich die Exception weiterwerfe, interessiert mich die Änderung
im nächsten catch-Block...Ja, aber im vorherigen catch-Block nicht mehr. Wo genau hilft mir jetzt ein const?
Außerdem kannst du ja (theoretisch - praktisch eher selten) einen Verweis
auf irgendein länger lebendes Heap-Objekt in deiner Exception haben.
Ohne const, könnstest du auf dieses Objekt ja auch schreibenden Zugriff erlangen.
Die Änderung dieses Objektes wird dich in deinem späteren Programmverlauf sicher
interessieren...Nein, das kann man ja gerade nicht, denn beim ersten Werfen wird immer eine Kopie angelegt:
void foo() { static int bar = 42; throw bar; // Kopie! }Wenn ich in diesem Fall per Referenz fange, wird einmal kopiert, wenn ich per Wert fange, wird (theoretisch) zweimal gefangen.
-
Michael E. schrieb:
Nein, das kann man ja gerade nicht, denn beim ersten Werfen wird immer eine Kopie angelegt
Du hast mich scheinbar nicht richtig verstanden...
Hier ein Beispiel, was ich meine:
#include<iostream> #include<vector> #include<string> class MyObject{ public: MyObject(const std::string& name) : name(name){ } void setName(const std::string& name){ this->name = name; } const std::string& getName() const{ return this->name; } private: std::string name; }; class DuplicateNameException{ public: DuplicateNameException(MyObject& object) : object(object){ } MyObject& getObject(){ return object; } const MyObject& getObject() const{ return object; } private: MyObject& object; }; void createObject(std::vector<MyObject*>& objectPool, const std::string& name){ for(std::vector<MyObject*>::const_iterator it = objectPool.begin(); it!=objectPool.end(); ++it){ if(name == (*it)->getName()){ throw DuplicateNameException(**it); } } objectPool.push_back(new MyObject(name)); } int main() { std::vector<MyObject*> objectPool; try{ createObject(objectPool, "test1"); createObject(objectPool, "test2"); createObject(objectPool, "test3"); createObject(objectPool, "test2"); } catch(DuplicateNameException& e){ // what shall I do? Probably rename original object? e.getObject().setName("new name"); } // catch(const DuplicateNameException& e){ // // what shall I do? Probably rename original object? // e.getObject().setName("new name"); // Ooh... I can't rename it... // } // Let's have a look at the objects (before deleting) for(std::vector<MyObject*>::const_iterator it = objectPool.begin(); it!=objectPool.end(); ++it){ std::cout << (*it)->getName() << std::endl; delete *it; } return 0; }Verstehst du jetzt was ich meine?
Von dem Pointer wird natürlich eine Kopie angelegt, aber das Objekt
darin hat einen anderen Besitzer, folglich wird es nicht kopiert.Ich weiß, die Objektzugehörogkeit ist RAII technisch nicht 100% sauber,
aber ich hätte das gleiche mit einer Pool-Klasse machen können.
Das Prinzip bleibt das gleiche, nur halt komplexer...
-
Da hast du recht: Wenn man innerhalb des geworfenen Objekts irgendwelche Zeiger oder Referenzen hat, dann werden natürlich nur die Verweise kopiert. Meine Exception-Klassen waren nie so komplex, dass mir das aufgefallen wäre (und ich hab mir deshalb nicht so tiefgehend Gedanken gemacht
). Wieder was gelernt.
-
Also ich fange immer per const&, da ich keinen Sinn darin sehe, eine gefangene Exception zu ändern. Egal ob ich sie danach weiterwerfen möchte oder nicht.
Wenn es an bestimmten Stellen Sinn machen sollte, dann würde ich genau dort das const weglassen und sonst nirgends.
Genau so mache ich es auch bei Funktionen: nur dort das const weglassen, wo es auch wirklich weggelassen werden sollte.