Zum Inhalt springen

[VC++] Exceptionhandling mit unique_ptr


Gateway_man

Empfohlene Beiträge

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

Link zu diesem Kommentar
Auf anderen Seiten teilen

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 von Klotzkopp
Link zu diesem Kommentar
Auf anderen Seiten teilen

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:

post-47975-14430449671914_thumb.png

Und so sieht das Handling aus (beachte was in dem Contextmenü bei _stackframe steht):

post-47975-14430449672104_thumb.png

LG

Gateway

Link zu diesem Kommentar
Auf anderen Seiten teilen

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

Link zu diesem Kommentar
Auf anderen Seiten teilen

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;
}

Link zu diesem Kommentar
Auf anderen Seiten teilen

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.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...