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()
returnschar const *
in case of single-byte character set andwchar_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 tochar 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.