在异常构造函数中参数化错误消息是一个好习惯吗?

时间:2015-11-02 01:04:27

标签: c++ exception printf

我想抛出一个异常,其中包含有关输入/结果导致问题的详细信息。然后,当我捕获这些异常时,我可以将有用的错误消息记录到日志中我正在研究VS2012,它没有实现参数包。所以目前我使用vsprintf将变量长度参数合并到字符串中。

  1. 在错误处理阶段使用此类printf-like函数是一种好习惯吗?

  2. 或者只是不需要在例外情况下携带这些详细信息?

  3. 例外

    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";
        }
    }
    

3 个答案:

答案 0 :(得分:2)

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

构建std::string可以throw.

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

答案 1 :(得分:1)

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

请务必将其换成使用可变参数模板和I / O流的类型安全解决方案 什么时候可以。

答案 2 :(得分: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;