如何避免将std :: string放在异常类中?

voi*_*ter 8 c++ exception-handling exception

这是我的异常类:

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();
}
Run Code Online (Sandbox Code Playgroud)

升压例外准则建议您不要将分配内存作为我的异常类成员的任何对象.在这种情况下,使用std::string违反了这一点.我尊重这个规则,但我想不出一种方法来实现what()覆盖而不使用std :: string来管理内存(而不是要求调用者为我管理它).

我可以使用固定大小的缓冲区作为成员并使用C库函数(如snprintf())来完成这项工作,但这对C++来说并不是非常惯用,因此不是理想的解决方案.

这是一个合适的异常类实现吗?如果没有,可以做出哪些改进?

Nat*_*nst 6

对于它的价值,所有的异常类型的定义<stdexcept>采取std::string作为参数.这可以由图书馆设计者解释为"好".我认为反对这一点的主要论点是,如果你处于一个内存受限的环境中,你可能无法分配内存来抛出异常.

  • `std :: exception`是抽象的,`what`是纯虚拟的,返回一个`const char*`.我同意,当你自己试图抛出时,调用可能抛出的东西是一个坏主意,但是如果没有堆分配,提供文本有意义的上下文可能会失败,这是非常困难的.还要注意,没有一个标准异常类型将它们的构造函数标记为`throw()`(查看前C++ 11).严格来说,在构造异常期间抛出并不是在异常中抛出 - 抛出不会在抛出表达式进行评估之前开始. (3认同)
  • 看看我的`stdexcept`(g ++ 4.1.2)的实现,没有技巧 - 有一个名为`_M_msg`的`std :: string`成员,例如`std :: logic_error`. (2认同)