5

I'm writing a library and want to return error codes whenever an error is returned by a remote system. The problem is that these are identified by strings, eg, "0A01" and also contain a message, and error code requires an integer as value.

What is the best way to implement an error code, with all the functionality that std::error_code provides but that uses strings as the value? How do I add an external error string to the std::error_code or std::error_category?

ruipacheco
  • 15,025
  • 19
  • 82
  • 138
  • 1
    Exceptions? --- – Quentin May 08 '17 at 20:21
  • I'd like to use error_codes. Fits better with the flow of the app. – ruipacheco May 08 '17 at 20:21
  • If there is a fixed number of those string codes, then you can map them to integer values (especially since they look like hex values) and use `std::error_code` anyway. Otherwise writing a class with two string fields should not be difficult at all. – freakish May 08 '17 at 20:25
  • Fixed number of codes. I guess I can subclass error_code and add another property. – ruipacheco May 08 '17 at 20:32
  • Are these strings composed only of hexadecimal digits? And short (not more than 8 characters)? – Ben Voigt Aug 22 '17 at 14:18
  • They're ascii, less than 8 characters yes. – ruipacheco Aug 22 '17 at 15:01
  • I think in order to give a useful answer it would be interesting whether you know all the possible errors and the associated messages at compile time. If you do not, you will need to manage those strings. Then you cannot directly use an error_code as that can only store an integer. You could somehow remember the strings in a map, however, create an integer id for each error and map back to the description in your custom `error_category::message` in this case. – PaulR Aug 22 '17 at 16:30
  • I guess I'd like to return unknown strings the same way we return them using std::error_category? – ruipacheco Aug 22 '17 at 16:47
  • Just a thought: hash the server error identifier strings into error numbers (and hope there are no collisions). Then write a custom error category where the message contains the original identifier string. This supposes that all possible server error IDs are known. – Emile Cormier Aug 22 '17 at 17:29

1 Answers1

3

As mentioned in the comments, you must know the error codes, which could be received from the remote server. The std::string which you receive from a remote server contains 2 parts as you said,

The problem is that these are identified by strings, eg, "0A01" and also contain a message, and error code requires an integer as value.

As you haven't shared the format of the error message, I am not adding the code for spiting it, split your string into 2 parts,

  1. Error Code
  2. Error Message

Now you can convert Error Code of type std::string to int by using std::stoi(error_code), So lets say

int error_code_int = std::stoi(string_to_hexadecimal(error_code));

And for std::error_category which serves as base class for our custom error messages, do this,

std::string message_received = "This is the message which received from remote server.";

struct OurCustomErrCategory : std::error_category
{
  const char* name() const noexcept override;
  std::string message(int ev) const override;
};

const char* OurCustomErrCategory::name() const noexcept
{
  return "Error Category Name";
}

std::string OurCustomErrCategory::message(int error_code_int) const
{
    switch (error_code_int)
    {
    case 1:
        return message_received;

    default:
        return "(unrecognized error)";
  }
}

const OurCustomErrCategory ourCustomErrCategoryObject;

std::error_code make_error_code(int e)
{
  return {e, ourCustomErrCategoryObject};
}

int main()
{
    int error_code_int = std::stoi(string_to_hexadecimal(error_code));  // error_code = 0A01
    ourCustomErrCategoryObject.message(error_code_int);
    std::error_code ec(error_code_int , ourCustomErrCategoryObject);
    assert(ec);

    std::cout << ec << std::endl;
    std::cout << ec.message() << std::endl;
}

The output for above working example is

Error Category Name : 0A01
This is the message which received from remote server.

You can use function string_to_hexadecimal() from this post.

I hope that now you can modify the above code according to your needs.

Edit 1:

As you said that:

This assumes the dynamic message is a global value. How do I pass it to an std::error_category object?

You can see that both std::error_code::assign and constructor std::error_code::error_code are taking parameters of int for error code number and error_category. So It is obvious that std::error_code can't take the dynamic message.

But wait, I said std::error_code are taking error_category as an argument in constructor, so is there any way, we can assign the dynamic message there ?

std::error_category states that:

std::error_category serves as the base class for specific error category types.

So it means that the struct we derived from std::error_category at the following line

struct OurCustomErrCategory : std::error_category

can have a data member and we can assign it via member function, so our struct will become like that,

struct OurCustomErrCategory : std::error_category
{
    std::string message_received;
    OurCustomErrCategory(std::string m) : message_received(m) {}

    const char* name() const noexcept override;
    std::string message(int ev) const override;
};

and you can assign it like that wherever you want,

const OurCustomErrCategory ourCustomErrCategoryObject("This is the message which received from remote server.");
Sahib Yar
  • 1,030
  • 11
  • 29
  • This assumes the dynamic message is a global value. How do I pass it to an std::error_category object? – ruipacheco Aug 23 '17 at 13:06
  • 1
    @ruipacheco: You can store the message in members of `OurCustomErrCategory` and add methods for you to store them if you only know them when they arrive from the network. This assumes that the mapping from error code to message is constant, i.e. if two error codes are identical, the messages will be identical. – PaulR Aug 23 '17 at 13:41
  • @ruipacheco Is there any issue in the code, how can I assist you ? – Sahib Yar Aug 25 '17 at 11:46
  • @SahibYar We need a static reference to std::error_category child and this means I can't overload make_error_code(). The code you wrote crashes. Check https://ned14.github.io/outcome/tutorial/error_code/ – ruipacheco Aug 25 '17 at 11:58
  • @SahibYar Gave you back the answer, I misunderstood my problem. – ruipacheco Aug 25 '17 at 12:08