19

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

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

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

  • 只是返回truefalse
  • 返回错误代码
  • 断言并记录
  • 抛出异常
  • 以上任意组合

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

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

4

9 回答 9

13

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

  • 错误代码 异常:异常和错误代码代表了如何处理结果代码的不同习惯用法。异常更加健壮 - 结果代码可以被忽略或丢失。库通常应该强烈区分抛出哪里/什么异常,以及何时使用错误代码。充其量,只使用两者之一。

  • return trueor false:错误代码的特殊化。通常是最糟糕的想法 - 只有在没有更多要报告的情况下才好或坏(即malloc返回好或坏(= NULL)。

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

于 2009-09-07T09:18:49.887 回答
11

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

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

于 2009-09-07T09:03:58.310 回答
5

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

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

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

于 2009-09-07T09:39:41.577 回答
3

我建议阅读 Boost 社区指南[boost.org] 以了解异常和错误处理。

于 2009-09-07T09:17:19.517 回答
2

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

因此,我将编写一个 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;
    }
}
于 2009-09-07T21:07:51.397 回答
2

选择什么策略通常是一个品味问题。我说选择最能与您图书馆的客户集成的东西。如果他们采用异常策略,请使用异常。如果他们习惯了错误代码,请坚持下去。

于 2009-09-07T09:03:14.427 回答
2

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

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

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

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

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

于 2009-09-07T09:30:58.030 回答
1
  • 如果您无法访问用于生成/读取错误报告的终端,则应使用日志记录。
  • 返回 True/False 应与错误代码结合使用。示例:函数在成功时返回 True,在错误时返回 False,并使用适当的错误代码/描述设置变量(全局或参数,您的选择)。
  • 例外:在我看来,最好将它们与日志记录和从错误中优雅恢复结合起来。如果这不可能,您不妨求助于错误代码,因为异常不会提供额外的好处。
  • assert():正如其他人指出的那样,它会在发布版本中编译掉,所以可以随意触发。

2c

于 2009-09-07T09:29:25.763 回答
0

首先 - 保持一致!

第二:

  • 只是真/假是不够的。它必须与错误代码相结合(例如 false + getLastError)。
  • 错误代码很快,但构建一些基础设施可以轻松地将它们转换为字符串。
  • 断言/日志:不,您希望应用程序能够对错误做出反应
  • 异常比错误代码慢,但更容易用困难的控制流进行编程。
  • 组合:只有真/假+错误代码组合,其余的保持一致,这意味着:不要组合。
于 2009-09-07T09:04:52.643 回答