C ++例外; int或std :: exception?

时间:2011-08-07 23:23:31

标签: c++ exception

我正在编写一些需要进行错误报告的库函数。我想使用异常而不是返回值。

我编写了抛出异常的函数。

例如:

if(strm->atEnd()){
    // unexpected end of stream
    throw -2;
}

我的问题是,这种方法好吗?或者我应该抛出从std :: exception派生的异常吗?

以什么方式更好地抛出std :: exception? (除了能够使用catch(std :: exception& e))

抛出异常坏习惯吗? (所有throw int值都记录在doxygen注释中)

我找不到任何理由为什么(在这种情况下)我应该抛出一个对象。

6 个答案:

答案 0 :(得分:18)

我会根据std::exception抛出异常。

throw std::runtime_error("unexpected end of stream")

我发现catch,log,等等更容易。它还允许从代码中删除注释和幻数。

然后可以将此消息发送给最终用户,使他们有希望解决问题。

用户和图书馆消费者无法阅读代码中的评论,他们不太可能知道“-2”的含义。

答案 1 :(得分:9)

例外行为的例外情况。他们是你应该担心优化的最后一件事!

唐纳德克努特说:

  

我们应该忘记小的效率,比如大约97%的时间:过早的优化是所有邪恶的根源

此外,作为例外的对象可能包含有关错误的信息。

例如,您有一个例外,意味着无法读取文件。如果抛出一个对象异常,该对象可能带有文件名,而这个名称不能包含整数。

如果异常来源未知(堆栈深处)并且没有人捕获它,如果异常是具有适当信息的对象,则调试程序会更容易。

答案 2 :(得分:7)

  

我的问题是,这种方法好吗?

考虑可读性。不会

throw CUnexpectedEndOfStream();

更具可读性
throw -2

在很多情况下,不会在调试器中看到抛出CUnexpectedEndOfStream的实例意味着TONS超过-2。更不用说CUnexpectedEndOfStream可以存储有关问题的大量有用信息,例如说无法读取的文件以及可能有关问题性质的更多信息。

  

或者我应该抛出从std :: exception派生的异常吗?

如果您选择组织其他例外情况,那么继承std::exception可能会有所帮助。它是客户端代码可以使用的方便基类。另外,根据例外情况,您可能需要使用std::runtime_error

  

抛出异常坏习惯吗? (所有throw int值都记录在doxygen注释中)

谁说这是不好的做法?抛出异常是处理异常情况的好方法。我抛出的大多数异常是因为客户端代码可能已经阻止了它应该做的事情 - 我的代码的用户违反了合同。但是还存在许多其他特殊的非正常情况,例如操作系统错误,磁盘填满等。所有不属于程序正常流程的东西。更重要的是,因为它们不是你的程序的正常流程,你不需要担心性能。

作为一个例子,我曾经使用异常来触发某个消息解析失败。但是,我发现这些解析错误经常发生,我开始处理异常并修复问题输入和重新分析。过了一会儿,我意识到更可读的解决方案是直接在解析代码中修复问题,并停止将其视为特殊情况。所有做出解析决策的代码都被放回到一个地方,而我并没有像醉酒的水手那样抛出咒语。

答案 3 :(得分:3)

您应该抛出源自std::exception的异常,例如std::runtime_error

大多数现有代码假设一个普通的C ++异常是std::exception,而其他任何东西都是“硬异常”,要传播到非常高的控制级别,如main

例如,现有代码很可能无法为int记录任何合理的消息。它只是“未知的异常类型”。

干杯&第h。,

答案 4 :(得分:0)

你为什么不这样做:

if(strm->atEnd()){
    // unexpected end of stream
    throw std::exception("-2");
}

throw -2不好,因为-2的类型既不是std::exception也不是std::exception

或者您最好将自己的课程编写为:

class FileException : std::exception
{
      //...
};

然后

 throw FileException("Unexpected end of stream");

更具可读性。

答案 5 :(得分:-6)

理论上,你总是可以抛出复杂的异常,但在大多数情况下你可能不需要。

  

我的问题是,这种方法好吗?

是和否。从理论上讲,你可以通过各种方式来做到这一点,但这不是一个好的做法(见下文)。但是,如果您仍然这样做,至少我会建议#define错误代码以获得更好的可读性。

#define UNEXPECTED_END_OF_STREAM -2

if(strm->atEnd()){
    // unexpected end of stream
    throw UNEXPECTED_END_OF_STREAM;
}

将-ve数字作为错误代码/异常抛出是非常罕见的,并且它很可能会被贬低。事实上,即使它会完全按照你想要做的事情(至少在大多数情况下),人们也会皱起眉头抛出int异常,即抓住错误。

我抛出的最常见的异常是std :: runtime_error(“我的错误”)`,它伪装成抛出一个简单的字符串异常。在大多数情况下,基本异常就是我们所需要的,检测错误并返回。

请记住,无论你抛出什么样的异常,你总能获得try-catch块的好处,这实际上是异常处理的核心。如果抛出int异常,情况也是如此。我想int很可能表示错误代码。有时可能需要这样说,如果你在dll的内部使用异常,但想要将错误代码返回给外界。我认为你的问题真的归结为这个问题,我可以抛出一个int例外,我应该吗?

请注意尽管可以这样做,但抛出int异常并不是最优雅的事情。为什么?因为int是原始数据时间,并且您希望在C ++中考虑面向对象,所以最好抛出一个对象。这可能意味着您可能必须将int错误代码封装到对象中并抛出该对象。也许当你这样做时,添加描述错误的字符串可能是个好主意。这是我过去所做的。我从std::runtime_error派生了我的异常类并添加了错误代码。

class my_error :    public std::runtime_error
{
public:
    my_error(std::string const& msg, int code);
    virtual ~my_error(void);

    // the error code which you want to throw
    int errCode;
};

现在,如果要抛出异常/错误代码,请执行以下操作:

throw my_error("this is my own error!", UNEXPECTED_END_OF_STREAM );