异常、错误代码、断言

发布于 2024-08-03 20:45:11 字数 553 浏览 3 评论 0原文

我正在开发一个生成设备报告的库。 generate_report (const std::string& no) 成员函数可能因各种原因而失败:

  1. 无效的报告号。
  2. 无效状态(report_generator 是 FSM)
  3. 没有设备处于活动状态
  4. 报告生成期间

错误哪种错误处理机制最适合这些错误?

  • 只需返回 truefalse
  • 返回错误代码
  • 断言和日志
  • 抛出异常
  • 上述任何组合

一些上下文信息:正常工作流程如下。用户激活设备,从列表中选择报告并单击“生成”。

编辑:感谢到目前为止的回复!对我来说,现在很清楚何时使用断言以及何时进行错误处理。对于错误处理,错误代码和异常各有利弊。我想我会寻求例外(并为上述错误创建四个类),但我还没有真正相信。我总是想到“意外情况”的例外情况。无效的报告号并不意外。有什么建议吗? :)

I'm working on a library that generates reports of devices. The generate_report (const std::string& no) member function can fail due to various reasons:

  1. invalid report no.
  2. invalid state (the report_generator is a FSM)
  3. no device is active
  4. error during report generation

Which error-handling mechanism is best for these errors?

  • just return true or false
  • return error code
  • assert and log
  • throw exception(s)
  • any combination of the above

Some context information: the normal workflow is as following. The user activates a devices, chooses a report from a list and clicks on "generate".

EDIT: Thanks for the replies so far! For me it's clear now when to use asserts and when to do error-handling. As for error-handling, error codes and exceptions both have pros and cons. I think I go for exceptions (and create four classes for the above errors), but I'm not yet really convinced. I always thought of exceptions of 'unexpected situations'. An invalid report no isn't really unexpected. Any advice? :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

毁虫ゝ 2024-08-10 20:45:11

其中任何一个都有不同的目的:

  • 错误代码版本。异常:异常和错误代码代表了如何处理结果代码的不同习惯用法。异常更加强大 - 结果代码可以被忽略或丢失。库通常应该强烈区分抛出异常的位置/内容以及何时使用错误代码。最好只使用两者之一。

  • 返回truefalse:错误代码的特殊化。
    通常是最糟糕的想法 - 只有当没有比好或坏更多的内容报告时才好(即 malloc 返回好或坏(= NULL)。

  • 断言和日志:这些是调试技术,不应该用作向用户/客户端的报告机制。断言只是说“发生了一些事情,我无法处理 - 我退出”。

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".

£冰雨忧蓝° 2024-08-10 20:45:11

断言不是正确的选择。当你有不变量时使用断言;一些不应该发生的事情。不要做像断言()这样的事情,如果参数是错误条件而不是不变量,则参数永远不会为空。

如果是我,我会在接口中使用异常,并且如果必须的话,如果内部使用的函数不使用异常,则通过内部使用的函数来翻译错误代码。只要保持一致(并且不要对这些东西使用断言)。

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).

維他命╮ 2024-08-10 20:45:11

与真/假和错误代码相比,异常有几个重要的优点:

  • 异常不能被忽略。如果您的代码引发异常,调用者必须捕获它以避免出现未处理的异常。
  • 异常可以在比直接调用者更高的级别上进行处理。如果您使用错误代码,您可能最终会遇到这样的情况:应用程序的所有层都必须检查错误并将其传递回调用者。

断言用于表达代码中的前提条件等内容,并有望在开发过程中发现任何错误。但是,您不应依赖发布代码中的断言,并且出于性能原因,断言通常会从发布代码中删除。

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.

染墨丶若流云 2024-08-10 20:45:11

我建议阅读 Boost 社区关于异常和错误处理的指南 [boost.org]。

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

入怼 2024-08-10 20:45:11

选择什么策略通常取决于品味。我说选择最适合您图书馆客户的产品。如果他们采用例外策略,就使用例外。如果他们习惯了错误代码,请坚持使用。

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.

是伱的 2024-08-10 20:45:11

您所报告的设备的可靠性如何?

我问这个问题是因为对于一大类设备来说,未连接、未打开、电池耗尽、忙于做其他事情等等都是相当正常的状态。

如果是这种情况,如果设备因某种原因不可用,我会倾向于返回状态代码(注意不是错误代码)。

另一方面,如果您认为这些设备超级可靠,并且它们不响应确实是例外,那么异常处理可能是正确的选择。

mutch 作为“异常”实际上只是一种编写“if (x != 0) { goto error_routine; ”的奇特方式,这并不重要。但是,我个人更喜欢异常处理来处理异常情况,而不是像 end_of_file 这样的常规事件。

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.

很酷又爱笑 2024-08-10 20:45:11

我将违背常规并建议错误代码和异常,但这只是因为您正在创建一个库。既然你说你正在创建一个库,我猜这个库将可供你无法控制的人编写的代码使用。因此,使您的代码对不同的编译器甚至语言都友好是一件好事。

因此,我将编写一个 C++ 异常库并提供详细说明异常类的头文件。我还将编写一个 C 接口来为用户处理异常。现在用户可以链接到任何合适的接口:

#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);

C 实现调用 C++ 实现:

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

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;
    }
}
陪我终i 2024-08-10 20:45:11
  • 如果您无权访问终端来生成/读取错误报告,则应使用日志记录。
  • 返回 True/False 应该与错误代码结合起来。示例:函数在成功时返回 True,在错误时返回 False,并使用适当的错误代码/描述设置变量(全局或参数,您的选择)。
  • 例外:在我看来,将它们与日志记录和从错误中优雅地恢复结合起来是很好的。如果这是不可能的,您不妨求助于错误代码,因为异常不会提供任何额外的好处。
  • assert():正如其他人指出的那样,它会在发布版本中编译,因此可以随意触发。

2c

  • 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

○闲身 2024-08-10 20:45:11

首先——保持一致!

第二:

  • 仅仅真/假是不够的。它必须与错误代码结合使用(例如 false + getLastError)。
  • 错误代码很快,但需要构建一些基础设施来轻松将它们转换为字符串。
  • 断言/日志:不,您希望应用程序能够对错误
  • 异常做出反应,速度比错误代码慢,但更容易使用困难的控制流进行编程。
  • 组合:仅 true/false + 错误代码组合,其余BE CONSISTENT 表示:不组合。

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.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文