std::exception::what() and Unicode



  • Hello! I use MSVS2008.

    I have exception class like this:

    class Exception: public std::exception
    {
    private:	
    	tError errorCode;
    
    public:
    	inline Exception(void): errorCode(eUnknownError) {;}
    	inline Exception(tError const errorCode): errorCode(errorCode) {;}
    
    	virtual char const *what() const throw() { return GetErrorMessage(errorCode); }
    };
    

    tError is some enum. GetErrorMessage() returns char const * in case of single-byte character set and wchar_t const * in case of Unicode enabled in the Project settings.

    Somewhere in the program error is shown by the following code:

    cout << "Error: " << e.what() << endl;
    return EXIT_FAILURE;
    

    The program does not compile when Unicode enabled because the result of GetErrorMessage() cannot be converted to char const * .

    How to rewrite the above pieces of code to make the program working with Unicode enabled?



  • virtual TCHAR const *what() const throw() { return GetErrorMessage(errorCode); }



  • @SAn:
    Something like this could work:

    class FooException : public std::exception
    {
    public:
        explicit FooException(std::string const& msg) : m_msg(new std::string(msg)) {}
        explicit FooException(std::wstring const& wmsg) : m_wmsg(new std::wstring(wmsg)) {}
    
        virtual char const* what() const
        {
            if (!m_msg)
                m_msg = ... // convert
            return m_msg->c_str();
        }
    
        virtual wchar_t const* wwhat() const
        {
            if (!m_wmsg)
                m_wmsg = ... // convert
            return m_wmsg->c_str();
        }
    
    private:
        boost::shared_ptr<std::string> mutable m_msg;
        boost::shared_ptr<std::wstring> mutable m_wmsg;
    };
    

    This is of course different from your approach to only store the error-code, and then look up a message when you need one.
    You cloud apply the "convert when needed" approach to your case however:

    class Exception: public std::exception
    {
    private:    
        tError errorCode;
    #ifdef UNICODE
        boost::shared_ptr<std::string> mutable m_buffer;
    #endif
    
    public:
        inline Exception(void): errorCode(eUnknownError) {;}
        inline Exception(tError const errorCode): errorCode(errorCode) {;}
    
    #ifdef UNICODE
        virtual char const *what() const throw() {
            m_buffer.reset( ... ); // convert to narrow character
            return m_buffer->c_str();
        }
    #else
        virtual char const *what() const throw() { return GetErrorMessage(errorCode); }
    #endif
    };
    

    And it would probably be best to add an additional accessor function that returns the wide character version directly.



  • Why are you using shared_ptr ?
    To keep buffer after destruction of class?

    But need this buffer be kept after destruction?
    What standard is saying about it?



  • Well...
    The copy-ctor of an exception class should never ever throw.

    If I would just use a direct std::(w)string member, the automatically generated copy-ctor could throw.

    The easiest and best solution I've found so far is to just use a shared_ptrstd::string (shared_ptr has a guaranteed no-throw copy-ctor).

    BTW: I forgot to remove the "throw()" spec from "what" - of course my implementation is no longer no-throw, so one should probably remove the spec.



  • @SAn:
    Why did you not use Bellis' tip. TCHAR ist exactly that what you need.
    If Unicode ist enabled, the type will be wchar_t otherwise char, so it will be always compatible will the return-type of GetErrorMessage.



  • He probably didn't use it because it's utter nonsense.
    The "what" method overrides std::exception's what, hence the signature and return-type must match.
    Changing the return-type to TCHAR is not an option.



  • Yes, you're right.


Anmelden zum Antworten