2015-11-02 53 views
1

我想抛出一个异常,提供有关哪些输入/结果导致问题的更详细的信息。然后,我可以将有用的错误消息记录到日志中,同时捕获这些异常。我正在处理VS2012,它没有实现参数包。所以目前我使用vsprintf将可变长度参数合并到字符串中。在异常构造函数中参数化错误消息是否是一种好的做法?

  1. 它是一个很好的做法,使用这种printf-like功能在错误处理阶段?

  2. 或者它只是不需要在异常中携带这些细节信息?

异常

class VargException : std::exception 
{public: 
    VargException (const char* fmt, ...) 
    { 
     va_list vargs; 
     va_start(vargs, fmt); 
     char buf[260] = {}; 
     vsprintf_s(buf, fmt, args); 
     va_end(vargs); 
     msgBuilt_ = tryAssign(msg_, buf); 
    } 
    const char* what() const { 
     return msgBuilt_? msg_.c_str(): "Error message failed to build"; 
    } 
    std::string msg_; 
    bool msgBuilt_; 

    // Updated: Avoid dynamic std::string throw exception 
    bool tryAssign(std::string& msg, const char* buf) throw() 
    { 
     try{ msg = buf; return true;} 
     catch (...) { return false; } 
    } 
}; 

客户端代码

void func(int key, int len) { 
    try { 
     if(notExists(key)) { throw VargException("%d key does not exist", key); } 
     if(outOfRange(len)) { throw VargException("length %d is out of range.", len); } 
     HRESULT hr = processSomething(); 
     if(FAILED(hr)) { throw VargException("FAILED to processingSomething. hr: 0x%08X", hr); } 
    } catch (VargException& e) { 
     std::cerr << e.what() << "\n"; 
    } 
} 
+1

@BaummitAugen'std :: exception'实际上没有。 'logic_error'和'runtime_error'。 –

+1

可以说'vsprintf'不是类型安全的。 – Jason

回答

2

在异常创建/处理代码中,您应该对异常更偏执。

构建std::string可以throw.

我想补充一点偏执,否则接受设计。查找一些令牌以检测2013模式并发出警告/弃用消息。

+0

是的,我从来没有想过创建std :: string可能会失败。这应该小心。但是,如果动态字符串有机会失败,是否意味着通过合并变量参数来构建结果消息很困难,同时抛出异常? (不管vsprintf/std :: stringstream/string :: opeator +) –

+0

这是否意味着我们应该在错误处理阶段保持任何操作的简单。固定字符串文字看起来像最安全的选项。 –

+0

我编辑的帖子增加了一个tryAssign函数来处理std :: string赋值,以避免从std :: string引发的异常。这可能更安全。 –

1

这似乎是一个合理的方法(除非你错过了一个参数vsprintf_s)。

只要确保使用可变参数模板和I/O流将其交换为类型安全的解决方案。
当你可以。

1

我发现它更容易使用std :: ostringstream而不是格式化字符串。

例如:

class MessageBuilder 
{ 
public: 
    MessageBuilder() {}; 

    MessageBuilder(const char * context) 
    { 
     m_os << context << ": "; 
    } 

    // stream operator to build message 
    template <class T> 
    MessageBuilder & operator<<(const T & t) 
    { 
     m_os << t; 
     return *this; 
    } 

    operator std::string() const 
    { 
     return m_os.str(); 
    } 

private: 
    std::ostringstream m_os; 
}; 

哪个可以用于这样建立的消息。

MessageBuilder() << "This is a message containing an int: " << 3; 
相关问题