What is the standard conforming way to decide what will be returned by what() from a class inherited from std::system_error without duplicating data?

Question!

I use a class inherited from std::system_error for error handling and I'd like to control what is returned when what() is called. Reason: the standard (both C++11 and the draft C++1y CD - N3690, � references below are into the latter) does not specify how exactly the string returned by what() shall look like, it just give a note in �19.5.6.2 (14):

Note: The returned NTBS might be the contents of what_arg + ": " + code.message(). � end note

so it shall be considered implementation dependent. (By the way, shouldn't it be code().message() instead of code.message()?)

So, the question is: how can I define precisely the string that what() returns if I want to be standard conformant and not relying on the implementation (i.e. want to be portable)?

For those, who prefer the code:

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?
        }
};

Ok, a trivial solution which I do not like could be the following:

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(); }
};

Since std::exception::what() is virtual, it will work, but is there a more elegant way without using any implementation detail? I do not like the idea of having two strings stored: one in std::system_error and the other in my_what.

The root of the problem: std::runtime_error � which happens to be std::system_error's parent class � has an exact requirement in �1.9.2.6 (3), a postcondition of the constructor:

strcmp(what(), what_arg.c_str()) == 0

Which, in the case of std::system_error becomes the following in �19.5.6.2 (2):

string(what()).find(what_arg) != string::npos

Does anybody have a clue why the standard tries so hard to include code().message() into what()? Note that code() returns the error code object, so anybody can include code().message() in the string at any time (even at the time when an exception of this class is catched).

If the requirement of std::system_error was the same as of std::runtime_error, I could just write:

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 */ )
        { }
};

Is there any elegant and portable solution?

UPDATE: Lots of the comments below are stating that the error messages are implementation defined. I understand that, I just want to format the string returned by what(), I do not want to be it byte-by-byte equivalent on all systems. Just think about that I want to log it or pass it to a 3rd party, and it shall obey some fixed format (which is not what is suggested by the standard).

UPDATE2: I believe that std::system_error is not just for OS or STL errors. I can (and suppose to) derive my own classes from it and use them for error reporting. What if I am writing a low level API? By the way, why is it forbidden to use it in a high level API?

If I pass all the arguments to its constructor in the error handling part of my API, there is no implementation defined (i.e. unknown) error strings involved, but I still can not format it without duplicating data.



Answers
I don't know of an "elegant and portable" solution, but I don't think there is anything wrong with the solution you propose in the question, which is to make your own copy of what_arg.

The exception object will not last very long: typically, only long enough to unwind the stack. Furthermore, the string in what_arg is not likely to be very long, given that a megabyte of what is not going to be very readable. And finally, the exception object will only be created in exceptional circumstances, so the "unnecessary" duplication of a small string is not going to have any noticeable impact on your program's performance.

Basically, the class designers have chosen to make the class's state opaque, and -- to put it bluntly -- you don't trust them to produce a usable result (a readable message) from that state. In that case, you will have to duplicate the state. This is a not uncommon consequence of state encapsulation, and the general solution is almost always to duplicate the state. In the case, the cost is minor, so if controlling the value of what() is important to you, you should just accept the cost and move on.

By : rici


I want to make a longer comment, so I'll post this as community wiki answer.

The Standard (C++14 draft N3690) describes system_error in [syserr.syserr.overview]/1:

The class system_error describes an exception object used to report error conditions that have an associated error code. Such error conditions typically originate from the operating system or other low-level application program interfaces.

Errors and error messages originating from the operating system or other low-level APIs are necessarily non-portable.

Furthermore, if you derive from system_error, someone who catches the exception by ref might expect the error codes from the OS / low level APIs as specified by the C++ implementation; at least this user knows the result of what() isn't guaranteed by the Standard. If this user catches an exception of your derived type, you might as well provide another what2() function that precisely returns your string.

The solution I'd propose is not to derive from system_error. As far as I can see, your analysis of the guarantees (and the typo code().message()) is correct, i.e. you cannot precisely specify the return of what() for system_error. If you want to have an error code in your exception, you could use the error_code facilities; yet, as with system_error, the Standard specifies in [syserr]/1

This subclause describes components that the standard library and C ++ programs may use to report error conditions originating from the operating system or other low-level application program interfaces.

Therefore, it might be better to use another error code type.

As far as I can see, deriving from system_error is useful if you want to enhance the error message from system_errors originating from the OS / low-level APIs. In that case, you might want to add some description to the message (what()), and this is what system_error guarantees for the message passed to the ctor.


Another "comment" to answer how you could derive from system_error and precisely specify the return of what():

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(); }
};

Yes, there's data duplication in the sense that there are (probably) two string objects, but there's no data duplication of the contents of the string. If you don't need to pass a string to the ctor of the exception (e.g. the type of the exception and the error code are descriptive enough), then you can even leave out the string object; something like

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"; }
};

Although it's probably better to include the error code in the description returned by what() (requires some sort of storage in my_class).

It might be worthwhile to mention that construction the string on demand (i.e. when what() is called) might be favourable.

By : DyP


This video can help you solving your question :)
By: admin