Quellcode Diskusion: Exception Basis Klasse
-
Hallo,
Ich möchte hier etwas Code zum diskutieren freigeben,#ifndef LOCATABLE_EXCEPTION_H_DIM #define LOCATABLE_EXCEPTION_H_DIM #include <exception> #include <string> namespace dim { class locatable_exception : public std::exception { public: locatable_exception(const std::string & file, int line, const std::string & what); const std::string & file() const; int line() const; virtual const char * what() const; private: const std::string file_; const int line_; const std::string what_; }; }// end of namespace dim #endif // #ifndef LOCATABLE_EXCEPTION_H_DIM
der Sinn dieser Klasse ist eine Basis Klasse bereit zu stellen die
if(...) throw dim::locatable_exception( __FILE__, __LINE__, "Ein Test" );
Man kann die Meldung z.b. ins MSVC Debug Fenster bringen und dann ist sie Doppelklickbar.
Hier ist die Implementierung Datei
#include "locatable_exception.h" namespace dim { locatable_exception::locatable_exception(const std::string & file, int line, const std::string & what) : file_( file ), line_( line ), what_( what ) { } const std::string & locatable_exception::file() const { return file_; } int locatable_exception::line() const { return line_; } const char * locatable_exception::what() const { return what_.c_str(); } }// end of namespace dim
Und hier ist auch gleich ein Kind von locatable_exception
#ifndef WINAPI_EXCEPTION_H_DIM #define WINAPI_EXCEPTION_H_DIM #include <iosfwd> #include <string> #include "locatable_exception.h" namespace dim { class winapi_exception : public dim::locatable_exception { public: typedef unsigned long DWORD; winapi_exception ( const std::string & file, int line, const std::string & error_message = "", DWORD winapi_error_code = GetLastErrorWrapper() ); DWORD winapi_error_code() const; const std::string winapi_error_message() const; private: static DWORD GetLastErrorWrapper(); static const std::string error_code_to_str(DWORD error_code); private: const DWORD winapi_error_code_; }; std::ostream & operator<< (std::ostream &, const winapi_exception &); void print_on_debug_screen(const winapi_exception & e); }// end of namespace dim #endif // #ifndef WINAPI_EXCEPTION_H_DIM
Ich habe versucht nicht die windows.h in mein Header zu includen, weil windows.h mit Makros verseucht ist.
Diese Exception versucht das low Level arbeiten mir ::GetLastError() zu wrappen.#include "winapi_exception.h" #include <ostream> #include <sstream> #include <windows.h> namespace dim { typedef winapi_exception::DWORD DWORD; winapi_exception::winapi_exception ( const std::string & file, int line, const std::string & error_message, DWORD winapi_error_code ) : dim::locatable_exception ( file, line, error_message ), winapi_error_code_ ( winapi_error_code ) { } DWORD winapi_exception::GetLastErrorWrapper() { return ::GetLastError(); } DWORD winapi_exception::winapi_error_code() const { return winapi_error_code_; } const std::string winapi_exception::winapi_error_message() const { return error_code_to_str( winapi_error_code_ ); } const std::string winapi_exception::error_code_to_str(DWORD error_code) { // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/formatmessage.asp class scope_auto_ptr // etwas umständlich, wenn ihr ein bessern weg kennt sicher zu stellen das { // der Speicher freigegeben wird, bitte zeigen (exception sicher bitte) public: scope_auto_ptr(void * p):p_( p ) { } ~scope_auto_ptr() { ::LocalFree( p_ ); } private: void * p_; scope_auto_ptr(const scope_auto_ptr &); scope_auto_ptr & operator= (const scope_auto_ptr &); }; void * message_buffer; DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; if(!::FormatMessage ( dwFormatFlags, NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language reinterpret_cast<LPTSTR>( &message_buffer ), 0, NULL )) return ""; scope_auto_ptr give_free_at_end( message_buffer ); return std::string( reinterpret_cast<LPTSTR>( message_buffer ) ); } std::ostream & operator<< (std::ostream & os, const winapi_exception & e) { os << e.file() << "(" << e.line() << "): \n"; os << "<winapi_error_message>" << e.winapi_error_message() << "</winapi_error_message>"; os << "<what>" << e.what() << "</what>"; return os; } void print_on_debug_screen(const winapi_exception & e) // ich weiß, die Funktionalität sollte in einen extra Stream { // auslagern std::ostringstream os; os << '\n' << e << '\n'; ::OutputDebugString( os.str().c_str() ); } } // end of namespace dim
wisst ihr was traurig ist? Ich habe an den ding zwei Tage rumgeschnippelt und im Grunde macht es nicht viel mehr als die Erste Version.
/edit mini_auto_ptr umbenant zu scope_auto_ptr
[ Dieser Beitrag wurde am 21.01.2003 um 01:01 Uhr von Dimah editiert. ]
-
hmm, ich verstehe den Sinn von der Nutzung des Auto-Pointers überhaupt nicht. Das kann man doch total einfach verhindern.
-
Ich meine so:
std::string s(reinterpret_cast<LPTSTR>(message_buffer)); LocalFree(message_buffer); return s;
-
@Dimah
Ohne mir deinen Code angeschaut zu haben, hast du mal einen Blick in Richard Nies' Artikel "Tracing Exceptions with an Exception Stack " (CUJ 04/2002) geworfen?
-
Link?
-
Link?
Leider keinen. Der Artikel ist meines Wissens nach nicht online.
-
Original erstellt von HumeSikkins:
@Dimah
Ohne mir deinen Code angeschaut zu haben, hast du mal einen Blick in Richard Nies' Artikel "Tracing Exceptions with an Exception Stack " (CUJ 04/2002) geworfen?ne mein abo startete erst mir 11/2002
Original erstellt von <bin>:
**Ich meine so:std::string s( reinterpret_cast<LPTSTR>( message_buffer ) ); LocalFree( message_buffer ); return s;
**
ja aber der ctor von std::string könnte eine exception throwen und dan würde message_buffer nie frei gegeben
ok dan manch man halttry { std::string s( reinterpret_cast<LPTSTR>( message_buffer ) ); LocalFree( message_buffer ); return s; } catch(...) // fängt alle exception { LocalFree( message_buffer ); throw; // schmeist die exception weiter }
aber was ist wenn in "return s" der CopyCtor throwt, dan wird versucht message_buffer zwei mal frei zu geben
nun gut dan könnte man das "return s" aus den try block raus nehmentry { std::string s( reinterpret_cast<LPTSTR>( message_buffer ) ); LocalFree( message_buffer ); } catch(...) { LocalFree( message_buffer ); throw; } return s; // schade geht nicht weil s hier nicht mehr lebt
ok dan so
std::string s; try { s = reinterpret_cast<LPTSTR>( message_buffer ); } catch(...) { LocalFree( message_buffer ); throw; } LocalFree( message_buffer ); return s;
aber jetzt könnte der Ctor "std::string s;" eine exception schmeissen,
try { std::string s; try { s = reinterpret_cast<LPTSTR>( message_buffer ); } catch(...) { LocalFree( message_buffer ); throw; } LocalFree( message_buffer ); return s; } catch(...) { LocalFree( message_buffer ); throw; }
so jetzt gehts /edit doch nicht, hier wird auch zwei mal message_buffer frei gegeben
nunja mir ist noch eine möglichkeit eingefallen
try { std::string s( reinterpret_cast<LPTSTR>( message_buffer ) ); LocalFree( message_buffer ); message_buffer = NULL; return s; } catch(...) { if(message_buffer) LocalFree( message_buffer ); throw; }
[ Dieser Beitrag wurde am 21.01.2003 um 00:02 Uhr von Dimah editiert. ]
[ Dieser Beitrag wurde am 21.01.2003 um 00:11 Uhr von Dimah editiert. ]