2011-08-07 58 views
11

我在写一些需要做一些错误报告的库函数。我想使用异常而不是返回值。C++异常; int或std :: exception?

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

如:

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

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

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

是否抛出int异常不良做法? (所有抛出的int值都记录在doxygen注释中)

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

+2

我可以做,当我在黑客的东西一起。但是当我完成它将始终生成一个真正的异常对象(从std :: rtuntime_error派生)。因为这简化了我所有的异常处理代码。假设你在main()中捕获它。你怎么知道哪个组件产生错误-345678? –

回答

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

这是更具可读性。

+2

因为它没有意义? – Johnsyweb

+4

我个人已经停止派生我自己的异常类(我只是使用std :: runtime_error);除非我有专门的例外可以捕捉和纠正的具体情况。如果我能做的只是日志,那么std :: runtime_error通常是最佳选择。注意:FileException可能应该从std :: runtime_error派生(因为std :: exception没有一个构造函数接收错误消息)子注:MS有一个非标准扩展std :: exception,允许您传递错误消息。 –

+0

为什么你会保留“-2”但将其作为例外原因? –

3

您应该抛出从std::exception(例如, std::runtime_error

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

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

干杯&心连心,

16

你应该扔掉基于std::exception异常。

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

试想多么容易这是catch,登录,等等。它还允许您删除无用的评论并从您的代码中删除一个幻数!

然后可以将此消息发送给最终用户,给他们解决问题的希望。他们无法读取代码中的注释,(不会读取您的Doxygen输出),他们不太可能知道“-2”的含义。

7

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

想想可读性。不会

throw CUnexpectedEndOfStream(); 

throw -2 

更具可读性?

而在很多情况下,不会在调试器中看到CUnexpectedEndOfStream的实例抛出的意思是TONS超过-2。这并不是说CUnexpectedEndOfStream可以存储关于该问题的有用信息,例如说明无法读取的文件以及有关问题性质的更多信息。

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

std::exception继承可能会有所帮助,如果这是你如何选择组织你的其他例外。它是客户端代码可以使用的便捷基类。也取决于您可能想要使用的例外std::runtime_error

抛出int异常不好的做法? (所有抛出的int值都记录在doxygen注释中)

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

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

+0

ISTM他特别要求抛出*** int exceptions异常***。 –

9

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

高德纳说:

我们应该忘记小的效率,讲的时候约97%:过早的优化是所有罪恶的根源

而且,对象异常可能携带有关错误的信息。

例如,您有一个异常,意味着无法读取文件。如果抛出一个对象异常,该对象可能会携带文件名,这是您不能使用整数的文件名。

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

-6

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

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

是的,没有。从理论上讲,你可以通过一切手段做到这一点,但它不是很好的做法(请阅读下文)。如果你仍然这样做,至少我会建议#define错误代码,以提高可读性。

#define UNEXPECTED_END_OF_STREAM -2 

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

将-ve数作为错误代码/异常抛出是非常罕见的,它很可能会被忽略。事实上,人们会皱起眉头,即使它会完全按照你想做的事情(至少在大多数情况下)抛出异常,那就是发现一个错误。

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

记住无论你抛出什么样的异常,你总能得到try-catch块的好处,这是异常处理的核心。如果抛出一个异常,情况也是如此。我想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); 
+1

-1:完全h h。通过发布这样的建议,你正在积极地损害C++社区。 –

+2

什么是史诗般的失败。 – Puppy

+0

@DeadMG它有什么问题? – zar