哪个,为什么,你更喜欢异常或返回代码? [英] Which, and why, do you prefer Exceptions or Return codes?

查看:28
本文介绍了哪个,为什么,你更喜欢异常或返回代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题是,对于错误处理、异常或错误返回代码,大多数开发人员更喜欢什么.请具体说明语言(或语系)以及您更喜欢其中一种的原因.

My question is what do most developers prefer for error handling, Exceptions or Error Return Codes. Please be language(or language family) specific and why you prefer one over the other.

我是出于好奇问这个的.就我个人而言,我更喜欢错误返回代码,因为它们的爆炸性较低,并且如果用户不愿意,也不会强迫用户代码支付异常性能损失.

I'm asking this out of curiosity. Personally I prefer Error Return Codes since they are less explosive and don't force user code to pay the exception performance penalty if they don't want to.

更新:感谢所有的回答!我必须说,尽管我不喜欢带有异常的代码流的不可预测性.关于返回码的答案(和他们的哥哥处理)确实给代码添加了很多噪音.

update: thanks for all the answers! I must say that although I dislike the unpredictability of code flow with exceptions. The answer about return code (and their elder brother handles) do add lots of Noise to the code.

推荐答案

对于某些语言(即 C++),资源泄漏不应成为原因

C++ 基于 RAII.

For some languages (i.e. C++) Resources leak should not be a reason

C++ is based on RAII.

如果您的代码可能会失败、返回或抛出(即最正常的代码),那么您应该将指针包裹在智能指针中(假设您有非常好的理由没有在堆栈上创建您的对象).

If you have code that could fail, return or throw (that is, most normal code), then you should have your pointer wrapped inside a smart pointer (assuming you have a very good reason to not have your object created on stack).

它们很冗长,并且往往会发展成类似:

They are verbose, and tend to develop into something like:

if(doSomething())
{
   if(doSomethingElse())
   {
      if(doSomethingElseAgain())
      {
          // etc.
      }
      else
      {
         // react to failure of doSomethingElseAgain
      }
   }
   else
   {
      // react to failure of doSomethingElse
   }
}
else
{
   // react to failure of doSomething
}

最后,你的代码是一组识别指令的集合(我在生产代码中看到了这种代码).

In the end, you code is a collection of idented instructions (I saw this kind of code in production code).

这段代码可以翻译成:

try
{
   doSomething() ;
   doSomethingElse() ;
   doSomethingElseAgain() ;
}
catch(const SomethingException & e)
{
   // react to failure of doSomething
}
catch(const SomethingElseException & e)
{
   // react to failure of doSomethingElse
}
catch(const SomethingElseAgainException & e)
{
   // react to failure of doSomethingElseAgain
}

将代码和错误处理完全分开,这可以是一件好事.

Which cleanly separate code and error processing, which can be a good thing.

如果不是来自某个编译器的一些模糊警告(参见phjr"的评论),它们很容易被忽略.

If not some obscure warning from one compiler (see "phjr" 's comment), they can easily be ignored.

在上面的例子中,假设有人忘记处理可能的错误(这发生了......).该错误在返回"时被忽略,并且可能会在稍后爆炸(即 NULL 指针).同样的问题不会发生例外.

With the above examples, assume than someone forgets to handle its possible error (this happens...). The error is ignored when "returned", and will possibly explode later (i.e. a NULL pointer). The same problem won't happen with exception.

错误不会被忽略.有时,你希望它不爆炸,但......所以你必须谨慎选择.

The error won't be ignored. Sometimes, you want it to not explode, though... So you must chose carefully.

假设我们有以下功能:

  • doSomething,它可以返回一个名为 NOT_FOUND_ERROR 的 int
  • doSomethingElse,它可以返回一个布尔值false";(失败)
  • doSomethingElseAgain,它可以返回一个 Error 对象(带有 __LINE__、__FILE__ 和一半的堆栈变量.
  • doTryToDoSomethingWithAllThisMess 其中,嗯...使用上述函数,并返回错误代码类型...

如果 doTryToDoSomethingWithAllThisMess 的一个被调用函数失败,它的返回类型是什么?

What is the type of the return of doTryToDoSomethingWithAllThisMess if one of its called functions fail ?

操作员不能返回错误代码.C++ 构造函数也不能.

Operators cannot return an error code. C++ constructors can't, too.

以上观点的推论.如果我想写怎么办:

The corollary of the above point. What if I want to write:

CMyType o = add(a, multiply(b, c)) ;

我不能,因为返回值已被使用(有时无法更改).所以返回值成为第一个参数,作为参考发送......或者不是.

I can't, because the return value is already used (and sometimes, it can't be changed). So the return value becomes the first parameter, sent as a reference... Or not.

您可以为每种异常发送不同的类.资源异常(即内存不足)应该很轻,但其他任何事情都可以根据需要很重(我喜欢 Java 异常给我整个堆栈).

You can send different classes for each kind of exception. Ressources exceptions (i.e. out of memory) should be light, but anything else could be as heavy as necessary (I like the Java Exception giving me the whole stack).

然后可以对每个捕获进行专门化.

Each catch can then be specialized.

通常,您不应隐藏错误.如果你不重新抛出,至少,将错误记录在一个文件中,打开一个消息框,无论如何......

Usually, you should not hide an error. If you do not re-throw, at the very least, log the error in a file, open a messagebox, whatever...

异常的问题是过度使用它们会产生充满尝试/捕获的代码.但问题出在别处:谁使用 STL 容器尝试/捕获他/她的代码?尽管如此,这些容器仍可以发送异常.

The problem with exception is that overusing them will produce code full of try/catches. But the problem is elsewhere: Who try/catch his/her code using STL container? Still, those containers can send an exception.

当然,在 C++ 中,永远不要让异常退出析构函数.

Of course, in C++, don't ever let an exception exit a destructor.

请务必在它们使您的线程瘫痪或在您的 Windows 消息循环内传播之前抓住它们.

Be sure to catch them before they bring out your thread on its knees, or propagate inside your Windows message loop.

所以我想解决方案是在应该发生的事情时抛出.当某些事情可能发生时,然后使用返回码或参数使用户能够对其做出反应.

So I guess the solution is to throw when something should not happen. And when something can happen, then use a return code or a parameter to enable to user to react to it.

所以,唯一的问题是什么是不应该发生的事情?"

So, the only question is "what is something that should not happen?"

这取决于你的函数的契约.如果函数接受一个指针,但指定指针必须是非 NULL,那么当用户发送一个 NULL 指针时抛出异常是可以的(问题是,在 C++ 中,函数作者何时没有使用引用来代替指针,但是...)

It depends on the contract of your function. If the function accepts a pointer, but specifies the pointer must be non-NULL, then it is ok to throw an exception when the user sends a NULL pointer (the question being, in C++, when didn't the function author use references instead of pointers, but...)

有时,您的问题是您不想要错误.使用异常或错误返回码很酷,但是...您想了解它.

Sometimes, your problem is that you don't want errors. Using exceptions or error return codes are cool, but... You want to know about it.

在我的工作中,我们使用一种断言".无论调试/发布编译选项如何,它都会根据配置文件的值:

In my job, we use a kind of "Assert". It will, depending on the values of a configuration file, no matter the debug/release compile options:

  • 记录错误
  • 打开一个带有嘿,你有问题"的消息框
  • 打开一个带有嘿,你有问题,要调试吗"的消息框

在开发和测试中,这使用户能够准确地在检测到问题时查明问题,而不是之后(当某些代码关心返回值时,或在 catch 中).

In both development and testing, this enable the user to pinpoint the problem exactly when it is detected, and not after (when some code cares about the return value, or inside a catch).

很容易添加到遗留代码中.例如:

It is easy to add to legacy code. For example:

void doSomething(CMyObject * p, int iRandomData)
{
   // etc.
}

导致一种类似于:

void doSomething(CMyObject * p, int iRandomData)
{
   if(iRandomData < 32)
   {
      MY_RAISE_ERROR("Hey, iRandomData " << iRandomData << " is lesser than 32. Aborting processing") ;
      return ;
   }

   if(p == NULL)
   {
      MY_RAISE_ERROR("Hey, p is NULL !
iRandomData is equal to " << iRandomData << ". Will throw.") ;
      throw std::some_exception() ;
   }

   if(! p.is Ok())
   {
      MY_RAISE_ERROR("Hey, p is NOT Ok!
p is equal to " << p->toString() << ". Will try to continue anyway") ;
   }

   // etc.
}

(我有类似的宏,仅在调试时有效).

(I have similar macros that are active only on debug).

注意,在生产中,配置文件不存在,所以客户端永远看不到这个宏的结果......但在需要时很容易激活它.

Note that on production, the configuration file does not exist, so the client never sees the result of this macro... But it is easy to activate it when needed.

当您使用返回码编码时,您正在为失败做好准备,并希望您的测试堡垒足够安全.

When you code using return codes, you're preparing yourself for failure, and hope your fortress of tests is secure enough.

当您使用异常编码时,您知道您的代码可能会失败,并且通常会在您的代码中选择战略位置放置反火捕获.但通常,您的代码更多的是关于它必须做什么";然后我担心会发生什么".

When you code using exception, you know that your code can fail, and usually put counterfire catch at chosen strategic position in your code. But usually, your code is more about "what it must do" then "what I fear will happen".

但是当您编写代码时,您必须使用您可以使用的最佳工具,有时,它是永远不要隐藏错误,并尽快显示它".我上面讲的宏遵循了这个理念.

But when you code at all, you must use the best tool at your disposal, and sometimes, it is "Never hide an error, and show it as soon as possible". The macro I spoke above follow this philosophy.

这篇关于哪个,为什么,你更喜欢异常或返回代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆