如何使用可变消息抛出std :: exceptions?

Ben*_*Ben 104 c++ exception-handling exception

这是我想要向异常添加一些信息时经常做的一个例子:

std::stringstream errMsg;
errMsg << "Could not load config file '" << configfile << "'";
throw std::exception(errMsg.str().c_str());
Run Code Online (Sandbox Code Playgroud)

有没有更好的方法呢?

Ker*_* SB 158

标准异常可以从以下构造std::string:

#include <stdexcept>

char const * configfile = "hardcode.cfg";
std::string const anotherfile = get_file();

throw std::runtime_error(std::string("Failed: ") + configfile);
throw std::runtime_error("Error: " + anotherfile);
Run Code Online (Sandbox Code Playgroud)

需要注意的是基类std::exception可以被这样构成; 你必须使用一个具体的派生类.


Tor*_*ten 44

这是我的解决方案:

#include <stdexcept>
#include <sstream>

class Formatter
{
public:
    Formatter() {}
    ~Formatter() {}

    template <typename Type>
    Formatter & operator << (const Type & value)
    {
        stream_ << value;
        return *this;
    }

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

    enum ConvertToString 
    {
        to_str
    };
    std::string operator >> (ConvertToString) { return stream_.str(); }

private:
    std::stringstream stream_;

    Formatter(const Formatter &);
    Formatter & operator = (Formatter &);
};
Run Code Online (Sandbox Code Playgroud)

例:

throw std::runtime_error(Formatter() << foo << 13 << ", bar" << myData);   // implicitly cast to std::string
throw std::runtime_error(Formatter() << foo << 13 << ", bar" << myData >> Formatter::to_str);    // explicitly cast to std::string
Run Code Online (Sandbox Code Playgroud)

  • 这与std :: stringstream有什么区别?它似乎包含一个字符串流,但有(据我所知),没有额外的功能. (3认同)
  • 通常,这不是100%安全的方法。std :: stringstream方法可能会引发异常。这里描述的问题相当不错:http://www.boost.org/community/error_handling.html (2认同)

Nee*_*asu 25

有不同的例外,例如runtime_error,range_error,overflow_error, logic_error,等等.你需要将字符串传递到它的构造,并且您可以连接任何你想你的消息.那只是一个字符串操作.

std::string errorMessage = std::string("Error: on file ")+fileName;
throw std::runtime_error(errorMessage);
Run Code Online (Sandbox Code Playgroud)

你也可以boost::format像这样使用:

throw std::runtime_error(boost::format("Error processing file %1") % fileName);
Run Code Online (Sandbox Code Playgroud)


Max*_*kin 16

以下类可能非常方便:

struct Error : std::exception
{
    char text[1000];

    Error(char const* fmt, ...) __attribute__((format(printf,2,3))) {
        va_list ap;
        va_start(ap, fmt);
        vsnprintf(text, sizeof text, fmt, ap);
        va_end(ap);
    }

    char const* what() const throw() { return text; }
};
Run Code Online (Sandbox Code Playgroud)

用法示例:

throw Error("Could not load config file '%s'", configfile.c_str());
Run Code Online (Sandbox Code Playgroud)

  • @MikeSeymour是的,但是如果你需要在中间放置字符串并以一定的精度格式化数字等,这会变得更加丑陋.在清晰度方面很难击败好的旧格式字符串. (9认同)
  • 不好的做法IMO,为什么在已经有一个为优化而构建的标准库的时候使用这样的东西? (4认同)
  • `throw std :: runtime_error("无法加载配置文件"+ configfile);`(如果需要,将一个或其他参数转换为`std :: string`). (4认同)
  • `throw std :: runtime_error(sprintf("无法加载配置文件'%s'",configfile.c_str())) (3认同)
  • 你能指出我这样的事情吗? (2认同)
  • @MikeSeymour我可能同意我发布的代码可能早于其时间。可移植的typesafe`printf`和C ++ 11中的朋友迫在眉睫。固定大小的缓冲区既是福也是祸:它在资源不足的情况下不会失败,但是可能会截断消息。我认为截断错误消息是更好的选择,然后失败。同样,格式字符串的便利性已被许多不同的语言证明。但是你是对的,这很大程度上取决于品味。 (2认同)

Shr*_*han 11

如果是C++ 14(operator ""s),请使用字符串文字运算符

using namespace std::string_literals;

throw std::exception("Could not load config file '"s + configfile + "'"s);
Run Code Online (Sandbox Code Playgroud)

或者在C++ 11中定义自己的if.例如

std::string operator ""_s(const char * str, std::size_t len) {
    return std::string(str, str + len);
}
Run Code Online (Sandbox Code Playgroud)

您的throw语句将如下所示

throw std::exception("Could not load config file '"_s + configfile + "'"_s);
Run Code Online (Sandbox Code Playgroud)

看起来很干净.

  • 我收到此错误** c ++ \ 7.3.0 \ bits \ exception.h | 63 |注意:没有匹配的函数可以调用'std :: exception :: exception(std :: __ cxx11 :: basic_string &lt;char&gt;)** (2认同)

evi*_*rix 6

也许是这个?

throw std::runtime_error(
    (std::ostringstream()
        << "Could not load config file '"
        << configfile
        << "'"
    ).str()
);
Run Code Online (Sandbox Code Playgroud)

它创建一个临时 ostringstream,根据需要调用 << 运算符,然后将其括在圆括号中,并对计算结果(这是一个 ostringstream)调用 .str() 函数,以将临时 std::string 传递给构造函数运行时错误。

注意: ostringstream 和字符串是临时右值,因此在该行结束后将超出范围。异常对象的构造函数必须使用复制或(更好的)移动语义获取输入字符串。

附加:我不一定认为这种方法是“最佳实践”,但它确实有效并且可以在紧要关头使用。最大的问题之一是此方法需要堆分配,因此运算符 << 可能会抛出异常。你可能不希望这种情况发生;然而,如果你进入这种状态,你可能有更多的问题需要担心!

  • 这似乎不起作用...`错误:'class std::basic_ostream&lt;char&gt;'没有名为'str'的成员`,另请参阅[this](/sf/ask/4163132781/ -member-named-str-in-stdbasic-ostreamchar-with-gcc-and-clang-but-no-p)。 (2认同)