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 halt

    try
        {
            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 nehmen

    try
        {
            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. ]


Anmelden zum Antworten