异常与错误代码与断言

时间:2009-09-07 09:00:26

标签: c++ exception error-handling assert

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

  1. 无效报告编号
  2. 无效状态(report_generator是FSM)
  3. 没有设备处于活动状态
  4. 报告生成期间
  5. 错误
  6. 哪种错误处理机制最适合这些错误?

    • 只需返回truefalse
    • 即可
    • 返回错误代码
    • 断言并记录
    • 抛出异常
    • 以上
    • 的任何组合

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

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

9 个答案:

答案 0 :(得分:12)

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

  • 错误代码vers。 exception(s):异常和错误代码表示如何处理结果代码的不同习惯用法。异常更加健壮 - 结果代码可以被忽略或丢失。库通常应该强烈区分抛出的异常/异常,以及何时使用错误代码。充其量只能使用其中之一。

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

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

答案 1 :(得分:11)

断言不是正确的选择。当你有一个不变量时使用断言;应该永远不会发生的事情。如果它是一个错误条件而不是一个不变量,那么不要执行assert()这样的参数永远不会为null。

如果是我,我会在界面中使用异常,如果必须的话,如果他们不使用异常,则通过内部使用的函数来转换错误代码。只是保持一致(并且不要使用断言)。

答案 2 :(得分:5)

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

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

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

答案 3 :(得分:3)

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

答案 4 :(得分:2)

选择策略往往是一种品味问题。我说要选择与你的图书馆客户最好的整合。如果他们采用例外策略,则使用例外。如果他们习惯于错误代码,请坚持下去。

答案 5 :(得分:2)

您报告的设备有多可靠?

我问,因为大量的设备没有连接,没有开机,没有电池,忙于做别的事情等等都是相当正常的状态。

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

另一方面,如果您认为这些设备非常可靠,那么他们不应该做出反应,那么异常处理可能是最佳选择。

mutch作为'exception'实际上只是一种代码'if(x!= 0){goto error_routine;但是,我个人更喜欢异常处理来处理异常情况,而不是像end_of_file这样的常规事件。

答案 6 :(得分: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;
    }
}

答案 7 :(得分:1)

首先 - 保持一致!

第二

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

答案 8 :(得分:1)

    如果您无权访问终端以生成/读取错误报告,则应使用
  • 日志记录。
  • 返回True / False应与错误代码结合使用。示例:函数成功时返回True,错误时返回False,并使用适当的错误代码/描述设置变量(全局或参数,您的选择)。
  • 例外:在我看来,将它们与日志记录和从错误中恢复的优雅恢复结合起来是很好的。如果无法做到这一点,您也可以使用错误代码,因为异常不会带来额外的好处。
  • assert():正如其他人指出的那样,它会在发布版本上进行编译,因此随意开火。

2C