Exception vs. error-code vs. assert

北慕城南 提交于 2019-11-28 18:22:19

Any of these have different purposes:

  • error code vers. exception(s): exceptions and error codes represent different idioms of how result codes shout be handled. Exceptions are more robust - result codes can be ignored or lost. A library should usually strongly distinguish where/what exceptions are thrown, and when error codes are used. At best, use only one of both at all.

  • return true or false: A specialization of error codes. Usually the worst idea - only good if there is no more to report than good or bad (i.e. malloc returns either good or bad (= NULL).

  • assert and log: These are debugging techniques, and should not be used as report mechanisms to users / clients. Asserts just say "something happened, that I can not handle - I quit".

assert is not the right choice. Use assert when you have an invariant; something that should never happen. Don't do things like assert() that an argument will never be null if it is an error condition and not an invariant.

If it were me, I would use exceptions in the interface and, if I had to, translate error codes by functions used internally if they do not use exceptions. Just be consistent about it (and don't use assert for this stuff).

Exceptions compared to true/false and error codes have several important advantages:

  • Exceptions cannot be ignored. If your code throws an exception the caller has to catch it to avoid getting an unhandled exception.
  • Exceptions can be handled at a higher level than the immediate caller. If you use error codes you may end up in situations where you at all layers of you application have to check for errors and pass them back to the caller.

Asserts are used to express stuff like preconditions in your code and will hopefully uncover any bugs during development. However, you should not rely on asserts in your release code, and for performance reasons asserts are normally removed from release code.

I recommend reading the Boost community guide [boost.org] to exceptions and error handling.

It is often a matter of taste what strategy to choose. I say pick up what best integrates with the clients of your library. If they adopt exception strategy, use exceptions. If they are accustomed to error codes, stick with it.

How reliable are the devices you are reporting on?

I ask because for a large class of devices not connected, not switched on, out of batteries, busy doing something else etc. etc. are fairly normal states.

If this is the case I would favour returning a status code (note not an error code ) if the device is somehow unavailable.

If on the other hand you consider these devices super reliable and it really is exceptional for them not to respond then exception handling may be the way to go.

It doesn't really matter that mutch as 'exceptions' are really just a fancy way to code 'if (x != 0) { goto error_routine; }, but, I personally prefer exception handling to deal with exceptional situations not routine events like end_of_file.

I'm going to go against the grain and suggest both error codes and exceptions, but only because you are making a library. Since you say you are making a library, I'm guessing that library will be made available to code written by people you have no control over. So, making your code friendly to different compilers and possibly even languages is a good thing.

So I would code a C++ exception library and provide header files detailing your exception classes. I would also code a C interface that handles the exceptions for the user. Now the user can link against which ever interface is appropriate:

#ifdef __cplusplus__
void generate_report(const std::string& rep_number, ostream& output);

extern "C" 
#endif
int generate_report(const char* rep_number, const char* outputfilename,
                    int* error_code, char* error_text, int max_error_text_len);

The C implementation calls the C++ implementation:

extern "C" 
int generate_report(const char* rep_number, const char* outputfilename,
                    int* error_code, char* error_text, int max_error_text_len)
{
    ofstream os;
    try {
        os.open(outputfilename, IOS_WRITE);
        generate_report(rep_number, os);
        os.close();
        return TRUE;
    } catch (base_exception& e) {
        os.close();
        if (error_code) *error_code = e.error_code();
        if (error_text) strncpy(error_text, e.str(), max_error_text_len);
        return FALSE;
    }
}

First - be consistent!

Second:

  • just true/false is not enough. It has to be combined with error codes (false + getLastError for example).
  • error-codes are fast, but build some infrastructure to convert them easily into strings.
  • assert/log: no, you want the application to be able to react on the error
  • exceptions are slower than error-codes, but easier to program with a difficult control flow.
  • combinations: only true/false + error codes combine, for the rest BE CONSISTENT which means: do not combine.
  • logging should be used if you don't have access to a terminal for producing/reading error reports.
  • returning True/False should be combined with error codes. Example: A function returns True on success, False on error, and sets a variable (global or parameter, your choice) with an appropriate error code/description.
  • exceptions: in my opinion, it's good to combine them with logging and graceful recovery from errors. If this is not possible, you might as well resort to error codes, as exceptions then provide no additional benefits.
  • assert(): As others have pointed out it compiles away on release builds, so fire at will.

2c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!