C++ 在不复制数据的情况下,确定What()从std::system_error继承的类返回什么的标准一致性方法是什么?

C++ 在不复制数据的情况下,确定What()从std::system_error继承的类返回什么的标准一致性方法是什么?,c++,c++11,c++14,system-error,C++,C++11,C++14,System Error,我使用从std::system\u error继承的类进行错误处理,并且我希望控制调用what()时返回的内容。原因:该标准(C++11和草案C++1y CD-N3690,§下文引用了后者)没有规定what()返回的字符串的确切外观,它只是在§19.5.6.2(14)中给出了一个注释: 注意:返回的NTB可能是what_arg+”的内容:+ code.message()-尾注 因此,应将其视为取决于实施情况。(顺便问一下,它不应该是code().message()而不是code.message(

我使用从
std::system\u error
继承的类进行错误处理,并且我希望控制调用
what()
时返回的内容。原因:该标准(C++11和草案C++1y CD-N3690,§下文引用了后者)没有规定
what()
返回的字符串的确切外观,它只是在§19.5.6.2(14)中给出了一个注释:

注意:返回的NTB可能是
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\u error
中,另一个在
my\u what

问题的根源:std::runtime_error——恰好是std::system_error的父类——在§1.9.2.6(3)中有一个确切的要求,构造函数的后条件:

strcmp(what(), what_arg.c_str()) == 0
如果出现
std::system_错误
,则该错误在§19.5.6.2(2)中变为以下情况:

有人知道为什么标准如此努力地将
code().message()
包含到
what()
中吗?请注意,
code()
返回错误代码对象,因此任何人都可以随时(甚至在捕获此类异常时)在字符串中包含
code().message()

如果
std::system\u error
的要求与
std::runtime\u 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()
返回的字符串进行格式化,我不想在所有系统上对其进行逐字节等效。试想一下,我想把它记录下来或传递给第三方,它应该遵循一些固定的格式(这不是标准建议的格式)

更新2: 我相信std::system_错误不仅仅针对操作系统或STL错误。我可以(并且假设)从中派生出我自己的类,并将它们用于错误报告。如果我正在编写一个低级API呢?顺便问一下,为什么禁止在高级API中使用它

如果我在API的错误处理部分将所有参数传递给它的构造函数,则不涉及实现定义(即未知)的错误字符串,但如果不复制数据,我仍然无法格式化它。

我不知道有什么“优雅且可移植”的解决方案,但我认为你在问题中提出的解决方案没有任何问题,那就是制作你自己的
what_arg

异常对象不会持续很长时间:通常,只会持续足够长的时间来展开堆栈。此外,
what_arg
中的字符串不太可能很长,因为一兆字节的
what
不太可读。最后,异常对象只会在异常情况下创建,因此小字符串的“不必要”复制不会对程序的性能产生任何明显的影响


基本上,类设计人员已经选择使类的状态不透明,并且——坦率地说——您不相信他们能从该状态生成可用的结果(可读的消息)。在这种情况下,您必须复制状态。这是状态封装的常见结果,一般的解决方案几乎总是复制状态。在这种情况下,成本很小,因此如果控制
what()
的值对您很重要,您应该接受成本并继续前进。

我想发表更长的评论,因此我将此作为社区wiki答案发布

标准(C++14草案N3690)在[syserr.syserr.overview]/1中描述了
系统错误

system\u error
描述了一个异常对象,用于报告具有相关错误代码的错误条件。这种错误情况通常源于操作系统或其他低级应用程序接口

来自操作系统或其他低级API的错误和错误消息必须是不可移植的

此外,如果您从代码>系统SytError 派生,如果使用REF捕获异常,则可能会期望来自C++实现的OS/低级别API的错误代码;至少该用户知道标准不保证的

what()
的结果。如果此用户捕获到派生类型的异常,您还可以提供另一个精确返回字符串的
what2()
函数

我建议的解决方案是而不是从
系统错误
中派生出来。据我所知,您对担保的分析(以及键入的
code().message()
)是正确的,即您无法精确指定
系统错误的
what()
返回值。 如果希望在异常中包含错误代码,可以使用
错误\u代码
工具;然而,与系统错误一样,标准在[syserr]/1中规定

本小节描述了标准库和C++程序可用于报告的组件
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 */ )
        { }
};
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)
        //            ^^^^ note: NOT passing the string
          , my_what( /* construct my what string */ )
    { }
    const char* what() const noexcept
    { return my_what.c_str(); }
};
class my_class : public std::system_error
{
public:
    my_class(std::error_code ec)
        : system_error(ec)
        //            ^^^^ note: NOT passing the string
    { }
    const char* what() const noexcept
    { return "description of error"; }
};