我使用继承自的类std::system_error
进行错误处理,并且我想控制what()
调用时返回的内容。原因:标准(C++11 和草稿 C++1y CD - N3690,下面的 § 引用属于后者)没有指定返回的字符串what()
应该是什么样子,它只是在 §19.5 中给出了注释.6.2 (14):
注意:返回的 NTBS 可能是
what_arg + ": " + code.message()
. ——尾注
所以它应该被认为是依赖于实现的。(顺便说一句,不应该code().message()
代替code.message()
吗?)
what()
所以,问题是:如果我想要符合标准并且不依赖于实现(即想要可移植),我该如何精确定义返回的字符串?
对于那些喜欢代码的人:
class my_class : public std::system_error {
public:
my_class(std::error_code ec, std::string const & what_arg)
: system_error(ec, /* this string is not required to be equal to what is returned by what() */)
{
// ok, try it here
// but what is the name of the member storing the string?
}
const char * what() const noexcept
{
// ok, try it here
// but how to access what_arg in its unaltered form?
}
};
好的,我不喜欢的一个简单的解决方案可能如下:
class my_class : public std::system_error {
std::string my_what;
public:
my_class(std::error_code ec, std::string const & what_arg)
: system_error(ec, what_arg),
my_what( /* construct my what string */ )
{ }
const char * what() const noexcept
{ return my_what.c_str(); }
};
既然std::exception::what()
是虚拟的,它就可以工作,但是有没有更优雅的方法而不使用任何实现细节?我不喜欢存储两个字符串的想法:一个std::system_error
在my_what
.
问题的根源:std::runtime_error——恰好是 std::system_error 的父类——在 §1.9.2.6 (3) 中有一个确切的要求,即构造函数的后置条件:
strcmp(what(), what_arg.c_str()) == 0
其中,std::system_error
在 §19.5.6.2 (2) 中变为以下内容:
string(what()).find(what_arg) != string::npos
有没有人知道为什么标准如此努力地包含code().message()
在内what()
?请注意,它code()
返回错误代码对象,因此任何人都可以随时将其包含code().message()
在字符串中(即使在捕获此类异常时)。
如果 的 要求与std::system_error
的 相同std::runtime_error
,我可以写:
class my_class : public std::system_error {
public:
my_class(std::error_code ec, std::string const & what_arg)
: system_error(ec, /* build my what string here */ )
{ }
};
有没有优雅便携的解决方案?
更新:下面的许多评论都指出错误消息是实现定义的。我明白,我只想格式化返回的字符串what()
,我不想在所有系统上都逐字节等效。想想我想记录它或将它传递给第三方,它应该遵循一些固定的格式(这不是标准所建议的)。
UPDATE2:我相信 std::system_error 不仅适用于操作系统或 STL 错误。我可以(并且假设)从中派生出我自己的类并将它们用于错误报告。如果我正在编写低级 API 怎么办?顺便问一下,为什么禁止在高级 API 中使用它?
如果我在我的 API 的错误处理部分将所有参数传递给它的构造函数,则不涉及实现定义(即未知)的错误字符串,但我仍然无法在不复制数据的情况下对其进行格式化。