3

For error handling, exceptions are problematic for me because my code is going to be a dynamically linked library. Furthermore I think exceptions should only be used in exceptional cases. But I will have cases where an error might occur that is not exceptional. Another problem is that my library will be called from C#. So using exceptions for all errors does not seem the right choice here.

But I find the concept of std::error_code and std::error_category quite pleasant and would like to use it in my application. However, I would also like to offer some kind of stack trace for errors.

Consider an example: The user wants to load a domain object from a database. To load this domain object the application needs to load rows from different tables. Suppose one of the required rows cannot be found. In this case the database layer would generate some "not found" error. If i propagate this error all up to the user the error message will not be very helpful because nobody knows what was not found. Likewise, if each layer handles the errors of the lower layer and generates a corresponding new error, abstracting the low level error, I would end up with something like "unable to load from database" which again is not very helpful. What I would like is to have both. That is each layer abstracts errors it gets from any lower level to be able to display descriptive messages to the end user but at the same time I don't want to lose information about the low level error. So I would like to have something like an error stack trace.

I thought about deriving from std::error_code and extend the class with a pointer to an underlying std::error_code and methods to get all these underlying objects. However, I am not sure if this technique would be a good idea because I read that care was taken when designing std::error_code to make it efficient.

We want error_code to be a value type that can be copied without slicing and without requiring heap allocation, but we also want it to have polymorphic behavior based on the error category.

EDIT I now think this technique would also introduce slicing problems, wouldn't it?

EDIT 2 I now think to implement it by deriving from std::error_code. Instead of a pointer, what would need heap allocation somewhere, my derived class would have a boost::optional. This way the inner error code could be created on the stack simply by copying it. A non-existing inner error code could be represented by boost::optional correctly. Slicing would still be a problem but I guess it is neglectable because the case of assigning an instance of my derived class to a std::error_code variable would not be necessary and even if it happens I would only loose information about the inner error codes. Furthermore I could provide a conversion from std::error_code to my derived class that has no inner error codes.

EDIT 3 I didn't think of that it is not possible to have a class containing a boost::optional of itself. So right now I don't see any possibility for what I would like to have without an allocation on the heap.

7
  • Why don't you define your own std::exception derived exception class with an inner_exception() method to return the inner exception (originated from lower level)? Your UI may even catch a business_exception but navigating through inner_exception() you may log everything did happen in each layer (well, if you want to do that, there may be security reasons to do not expose underlying details). Commented Feb 11, 2014 at 12:26
  • Oh BTW IMO std::error_code and std::error_category aren't right concept for your scenario. Application should use exceptions to notify errors, error codes are a heritage of a non-C++ environment (for example Operating System API or device drivers). In this case IMO you should create a wrapper around that functions encapsulating their error codes with std::error_code; expose them with a C++ish interface then manage errors in your application using exceptions (with your own exception with a error_code() member to get low level error code (if any). Commented Feb 11, 2014 at 12:32
  • I can't use exceptions because the code I'm writing is supposed to be a dynamically linked library Commented Feb 11, 2014 at 12:57
  • You can use them if all involved modules are C++ and they use same compiler. If not then even std::error_code won't work (and you have to go back to an int). If for any reason you want to rely on error codes (but they should be used for compatibility only, IMO) then you can apply same technique (error_code is a non sealed class) Commented Feb 11, 2014 at 13:07
  • 1
    As I mentioned exceptions are not an option for me. Commented Feb 11, 2014 at 16:07

1 Answer 1

1

Finally I'm deriving from std::error_code. My derived class has a member that is a pointer to an instance of the same class. I added a wrap() method to that class that takes an instance of the same class as argument and allocates a copy of it on the heap. The destructor of my derived class ensures that the memory is freed again. I added a getter method for this inner error code as well. This way i can stack several error codes. Drawback is, that I need heap allocation, but I simply hope, that in my scenario this will not cause significant performance issues. My class also provides conversion from std::error_code.


class my_error : public std::error_code { public: my_error() : std::error_code(), m_innerError(NULL) {}; my_error( int val, const std::error_category & cat ) : std::error_code(val, cat), m_innerError(NULL) {}; my_error( std::error_code & error ) : std::error_code(error), m_innerError(NULL) {}; my_error( const std::error_code & error ) : std::error_code(error), m_innerError(NULL) {}; ~my_error() { delete m_innerError; } template <class ErrorCodeEnum> my_error(ErrorCodeEnum e, typename boost::enable_if<std::is_error_code_enum<ErrorCodeEnum> >::type* = 0) { *this = make_custom_error(e); } template<typename ErrorCodeEnum> typename boost::enable_if<std::is_error_code_enum<ErrorCodeEnum>, error_code>::type & operator=( ErrorCodeEnum val ) { *this = make_custom_error(val); return *this; } my_error const * get_inner() const { return m_innerError; }; void wrap( const my_error & error) { m_innerError = new my_error(error); }; private: my_error * m_innerError; }; 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.