Here is my exception class:
class Win32Failure : public std::exception
{
public:
Win32Failure( char const* win32_function_name, LONG error_code );
char const* win32_function_name() const { return win32_function_name_; }
LONG error_code() const { return error_code_; }
virtual char const* what() const;
private:
std::string GetFormattedMessage() const;
char const* win32_function_name_;
LONG error_code_;
std::string error_text_;
};
Win32Failure::Win32Failure( char const* win32_function_name, LONG error_code )
: error_code_(error_code)
, win32_function_name_(win32_function_name)
{
std::stringstream error_msg;
error_msg << win32_function_name << " failed with code: "
<< error_code << " (" << GetFormattedMessage() << ")"
;
error_text_ = error_msg.str();
}
std::string Win32Failure::GetFormattedMessage() const
{
TCHAR message_buffer[1000];
FormatMessage(
//FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
error_code_,
0, // Default language
reinterpret_cast<LPTSTR>(&message_buffer),
sizeof(message_buffer) / sizeof(TCHAR),
NULL
);
return std::string(message_buffer);
}
char const* Win32Failure::what() const
{
return error_text_.c_str();
}
The boost exception guidelines recommend not placing any objects that allocate memory as members of my exception class. In this case, the usage of std::string violates this. I respect the rule for this, however I can’t think of a way to implement the what() override without using std::string to manage the memory (versus requiring the caller to manage it for me).
I could use a fixed-size buffer as a member and use C library functions (like snprintf()) to do the job, but this isn’t very idiomatic to C++ and thus not an ideal solution.
Is this a suitable implementation of an exception class? If not, what improvements can be made?
For what it’s worth, all of the exception types defined in
<stdexcept>takestd::stringas arguments. This could be interpreted by the library designers that it is “ok”. I think the main argument against this is if you’re in a memory constrained environment, you may not be able to allocate memory to throw your exception.