Gateway_man Geschrieben 9. September 2013 Geschrieben 9. September 2013 Hallo, eventuell mach ich mir momentan zu viele Gedanken darüber, dennoch kann ich das jetzt so nicht stehen lassen. Ich schreibe mir momentan eine Basisklasse welche ich für das Exceptionhandling verwenden will. Diese Klasse beinhaltet ein paar Pointer variablen. Wenn ich jetzt den Fehler jetzt wie folgt werfe: throw ExceptionBase(.....); Dann habe ich folgendes Phänomen im Catch Block: Alle Felder sind richtig bis auf die Pointer Variablen. Deren Wert ist überall <schlechtes ptr> (steht wirklich so drin nicht mein grammatikalischer Fehler). Ich lehn mich jetzt mal weit aus dem Fenster und vermute mal das er eine Kopie des ExceptionBase Objekts macht und dabei Probleme mit den Pointern hat. (Wie C++ sich beim Exceptionhandling wirklich verhält, entzieht sich jedoch meinen Kenntnissen) Das Problem kann ich beheben indem ich das ExceptionBase Objekt beim Throw als Pointer erzeugen lasse: throw new ExceptionBase(.....); Ich hatte jetzt nur etwas schiss, das wenn ich das so überall mache und ich irgendwo mal vergesse im Catch Block den Pointer zu handlen, das ich dann Speicherleaks verursache. Also habe ich versucht einen Smart Pointer beim throw zu erzeugen: throw std::unique_ptr<ExceptionBase>(new ExceptionBase(0xF50,0, "Invalid datetime information.", frame)); Da meckert er noch nicht und alles scheint super. Allerdings meckert er beim Catch Block: catch (std::unique_ptr<ExceptionBase> ex) Dort bringt er folgenden fehler: error C2316: 'std::unique_ptr<_Ty>': Kann nicht aufgefangen werden, da auf den Destruktor und/oder den copy-Konstruktur nicht zugegriffen werden. Das liegt offensichtlich daran das der Destruktor von unique_ptr nicht öffentlich zugänglich ist. Wie würdet ihr das Lösen? Ich spiel jetzt gerade mit dem Gedanken mir ein eigenes "Smart Pointer" Template zu schreiben, das über einen öffentlichen Destruktor verfügt. LG Gateway Zitieren
Klotzkopp Geschrieben 9. September 2013 Geschrieben 9. September 2013 (bearbeitet) Das liegt offensichtlich daran das der Destruktor von unique_ptr nicht öffentlich zugänglich ist. Nein, das liegt am Copy-Konstruktor. std::unique_ptr ist nicht kopierbar, und das ist ganz bewusst so. Wenn du "by value" fängst, wird von dem, was du fängst, eine Kopie erzeugt. Die Lösung ist ganz einfach: Throw by value, catch by reference: throw ExceptionBase(...); catch(ExceptionBase& ex)[/code] Bearbeitet 9. September 2013 von Klotzkopp Zitieren
Gateway_man Geschrieben 9. September 2013 Autor Geschrieben 9. September 2013 Hi, danke für deine fixe Antwort. Aber das habe ich bereits ausprobiert, leider mit mäßigem Erfolg. Alle werte des ExceptionBase Objekts die keine Pointer sind, sind zugreifbar, alle anderen sind wieder <schlechtes ptr> und ich kassier nach dem Catch Block eine Fehlermeldung (ungültiger Speicherzugriff...). So wird die Exception geworfen: Und so sieht das Handling aus (beachte was in dem Contextmenü bei _stackframe steht): LG Gateway Zitieren
Gateway_man Geschrieben 9. September 2013 Autor Geschrieben 9. September 2013 Danke für deine Hilfe. Habs hinbekommen . Ich habe die rohe Zeigervariable in ExceptionBase rausgeschmissen (Wie du es mir immer sagst. Finger weg von rohen Zeigern ). Jetzt musste ich leider einen Standartkonstruktor für StackFrame erstellen (Parameterlos) und das wollte ich eigentlich nicht . Um das ganze zu lüften: struct StackFrame { private: int _line; std::string _assembly, _functionname, _filename; public: //Standartkonstruktor hinzugefügt StackFrame(); StackFrame(int lineNumber, std::string assembly, std::string functionName, std::string filename); int Line(); std::string Assembly(); std::string FunctionName(); std::string Filename(); }; StackFrame::StackFrame() { } StackFrame::StackFrame(int lineNumber, std::string assembly, std::string functionName, std::string filename) { _line = lineNumber; _assembly = assembly; _functionname = functionName; _filename = filename; unsigned pos = _filename.find_last_of("\\"); if (pos >= 0) _filename = _filename.substr(pos +1); } int StackFrame::Line() { return _line; } std::string StackFrame::Assembly() { return _assembly; } std::string StackFrame::FunctionName() { return _functionname; } std::string StackFrame::Filename() { return _filename; } Hier die ExceptionBase Klasse (Änderungen auskommentiert!): class ExceptionBase { private: long _errorcode, _oserrorcode; std::string _message; //StackFrame* _stackframe; StackFrame _stackframe; public: ExceptionBase(int errorcode, int oserrorcode, std::string _message, /*StackFrame* frame*/ StackFrame& frame); long ErrorCode(); long OsErrorCode(); ~ExceptionBase(); std::string Message(); //StackFrame* GetStackFrame(); StackFrame GetStackFrame(); }; ExceptionBase::ExceptionBase(int errorcode, int oserrorcode, std::string message, /*StackFrame* frame*/ StackFrame& frame) { _errorcode = errorcode; _oserrorcode = oserrorcode; _message = message; _stackframe = frame; } ExceptionBase::~ExceptionBase() { //if (_stackframe != 0) // delete _stackframe; } long ExceptionBase::ErrorCode() { return _errorcode; } long ExceptionBase::OsErrorCode() { return _oserrorcode; } std::string ExceptionBase::Message() { return _message; } //StackFrame* ExceptionBase::GetStackFrame() //{ // return _stackframe; //} StackFrame ExceptionBase::GetStackFrame() { return _stackframe; } LG & Danke Gateway Zitieren
Klotzkopp Geschrieben 10. September 2013 Geschrieben 10. September 2013 Du brauchst keinen Default-Konstruktor für Stackframe, wenn du im ExceptionBase-Konstruktor eine Initialisierungsliste verwendest, statt alle Member im Konstruktorrumpf zuzuweisen. Das solltest du dir ohnehin angewöhnen. Und übergib frame als const-Referenz. ExceptionBase::ExceptionBase(int errorcode, int oserrorcode, std::string message, StackFrame const & frame) : _errorcode(errorcode), _oserrorcode(oserrorcode), _message(message), _stackframe(frame) { }[/code] Allgemein solltest du auf const-Correctness achten. Methoden, die den beobachtbaren Zustand des Objekts nicht ändern (z.B. Getter) sollten const sein, denn nur so kannst du sie auch mit einem const-Objekt aufrufen: [code] int Line() const; std::string Assembly() const; // usw. ... int StackFrame::Line() const { return _line; } Zitieren
Gateway_man Geschrieben 10. September 2013 Autor Geschrieben 10. September 2013 Danke für deine Hilfe. Ich werde mir das mal angewöhnen. Zitieren
Empfohlene Beiträge
Dein Kommentar
Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.