C++ 如何使用可变消息抛出 std::exceptions?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12261915/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to throw std::exceptions with variable messages?
提问by Ben
This is an example of what I often do when I want to add some information to an exception:
这是我想向异常添加一些信息时经常做的一个例子:
std::stringstream errMsg;
errMsg << "Could not load config file '" << configfile << "'";
throw std::exception(errMsg.str().c_str());
Is there a nicer way to do it?
有没有更好的方法来做到这一点?
采纳答案by Torsten
Here is my solution:
这是我的解决方案:
#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 &);
};
Example:
例子:
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
回答by Kerrek SB
The standard exceptions can be constructed from a std::string
:
标准异常可以从 a 构造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);
Note that the base class std::exception
can notbe constructed thus; you have to use one of the concrete, derived classes.
需要注意的是基类std::exception
可以不被这样构成; 您必须使用具体的派生类之一。
回答by Neel Basu
There are different exceptions such as runtime_error
, range_error
, overflow_error
, logic_error
, etc.. You need to pass the string into its constructor, and you can concatenate whatever you want to your message. That's just a string operation.
有不同的例外,例如runtime_error
,range_error
,overflow_error
, logic_error
,等等。你需要将字符串传递到它的构造,并且您可以连接任何你想你的消息。这只是一个字符串操作。
std::string errorMessage = std::string("Error: on file ")+fileName;
throw std::runtime_error(errorMessage);
You can also use boost::format
like this:
你也可以boost::format
这样使用:
throw std::runtime_error(boost::format("Error processing file %1") % fileName);
回答by Maxim Egorushkin
The following class might come quite handy:
下面的类可能会派上用场:
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; }
};
Usage example:
用法示例:
throw Error("Could not load config file '%s'", configfile.c_str());
回答by Shreevardhan
Use string literal operator if C++14 (operator ""s
)
如果 C++14 ( operator ""s
)使用字符串文字运算符
using namespace std::string_literals;
throw std::exception("Could not load config file '"s + configfile + "'"s);
or define your own if in C++11. For instance
或者在 C++11 中定义你自己的 if。例如
std::string operator ""_s(const char * str, std::size_t len) {
return std::string(str, str + len);
}
Your throw statement will then look like this
您的 throw 语句将如下所示
throw std::exception("Could not load config file '"_s + configfile + "'"_s);
which looks nice and clean.
看起来漂亮干净。
回答by Arthur P. Golubev
A really nicer way would be creating a class (or classes) for the exceptions.
一个更好的方法是为异常创建一个(或多个)类。
Something like:
就像是:
class ConfigurationError : public std::exception {
public:
ConfigurationError();
};
class ConfigurationLoadError : public ConfigurationError {
public:
ConfigurationLoadError(std::string & filename);
};
The reason is that exceptions are much more than just transferring a string. Providing different classes for the errors, you give developers a chance to handle a particular error in a corresponded way (not just display an error message). People catching your exception can be as specific as they need if you use a hierarchy.
原因是异常不仅仅是传输字符串。为错误提供不同的类,您可以让开发人员有机会以相应的方式处理特定错误(不仅仅是显示错误消息)。如果您使用层次结构,捕获您的异常的人员可以根据需要具体化。
a) One may need to know the specific reason
a) 可能需要知道具体原因
} catch (const ConfigurationLoadError & ex) {
// ...
} catch (const ConfigurationError & ex) {
a) another does not want to know details
a) 另一个不想知道细节
} catch (const std::exception & ex) {
You can find some inspiration on this topic in https://books.google.ru/books?id=6tjfmnKhT24CChapter 9
您可以在https://books.google.ru/books?id=6tjfmnKhT24C第 9 章中找到有关此主题的一些灵感
Also, you can provide a custom message too, but be careful - it is not safe to compose a message with either std::string
or std::stringstream
or any other way which can cause an exception.
此外,您也可以提供自定义消息,但要小心 -使用std::string
或std::stringstream
或任何其他可能导致异常的方式编写消息是不安全的。
Generally, there is no difference whether you allocate memory (work with strings in C++ manner) in the constructor of the exception or just before throwing - std::bad_alloc
exception can be thrown before the one which you really want.
通常,在异常的构造函数中或在std::bad_alloc
抛出之前分配内存(以 C++ 方式处理字符串)没有区别 -异常可以在您真正想要的异常之前抛出。
So, a buffer allocated on the stack (like in Maxim's answer) is a safer way.
因此,在堆栈上分配缓冲区(如 Maxim 的回答)是一种更安全的方法。
It is explained very well at http://www.boost.org/community/error_handling.html
它在http://www.boost.org/community/error_handling.html 中有很好的解释
So, the nicer way would be a specific type of the exception and be avoiding composing the formatted string (at least when throwing).
因此,更好的方法是使用特定类型的异常并避免组合格式化字符串(至少在抛出时)。