什么是标准的符合方式来决定从std :: system_error继承的类中的what()返回什么而不重复数据?

Nor*_*rci 8 c++ c++11 system-error c++14

我使用从继承的类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?
        }
};
Run Code Online (Sandbox Code Playgroud)

好吧,我不喜欢的一个简单的解决方案可能如下:

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(); }
};
Run Code Online (Sandbox Code Playgroud)

既然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
Run Code Online (Sandbox Code Playgroud)

其中,在std::system_error§19.5.6.2(2)中成为以下内容:

string(what()).find(what_arg) != string::npos
Run Code Online (Sandbox Code Playgroud)

没有任何人有一个线索,为什么标准试图这么难包括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 */ )
        { }
};
Run Code Online (Sandbox Code Playgroud)

有没有优雅和便携的解决方案?

更新:下面的许多评论都说明错误消息是实现定义的.据我所知,我只想格式化返回的字符串what(),我不想在所有系统上逐字节等效.想想我想记录它或将它传递给第三方,它应该遵循一些固定的格式(这不是标准建议的).

UPDATE2:我相信std :: system_error不只是OS或STL错误.我可以(并且假设)从中派生自己的类并将它们用于错误报告.如果我正在编写低级API怎么办?顺便说一句,为什么禁止在高级API中使用它?

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

ric*_*ici 6

我不知道"优雅和便携"的解决方案,但我认为你在问题中提出的解决方案没有任何问题,即制作你自己的副本what_arg.

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

基本上,类设计者选择使类的状态不透明,并且 - 直言不讳 - 你不相信它们从该状态产生可用的结果(可读消息).在这种情况下,您将不得不复制州.这是状态封装的一种并不罕见的结果,一般的解决方案几乎总是复制状态.在这种情况下,成本很小,因此如果控制价值what()对您来说很重要,您应该接受成本并继续前进.