如何使用过程语言处理异常?

时间:2009-09-15 11:05:43

标签: perl exception-handling

如何使用C或Perl等过程语言进行异常处理? (我知道Perl也做OO。)在Perl的过程代码中处理异常的最佳方法是什么?

6 个答案:

答案 0 :(得分:7)

在Perl 5中,使用evaldie完成了异常处理。您只需评估代码体,如果它死了,您可以检查$@是否有错误。如果你想要正确地做到这一点并不是那么容易,这就是各种try / catch模块存在的原因。您可能对没有依赖关系的Try::Tiny感兴趣,并描述了使用naive eval异常处理时必须处理的所有问题。 (另请参阅Try :: Tiny的作者this blog post。)

答案 1 :(得分:2)

以下是我在Perl中如何执行异常的示例(不使用其中一个Try模块):

use Carp;
use English qw( -no_match_vars );

do_something_needing_rollback_if_failed();
eval {
    do_something_dangerous();
} or do {
   # Exception was thrown by dangerous method
   # Save the error:
   my $error = $EVAL_ERROR;

   # Try to rollback
   eval { rollback(); }
     or do { confess qq{Couldn't rollback: $EVAL_ERROR. Original error $error}; }

   # Let's rethrow:
   confess qq{Rolled back! Error was $error};
}

Perl异常处理中一个比较烦人的部分是它使用单个变量来存储任何异常错误,并且它可能会被意外覆盖,因此需要一些防御性编码。

答案 2 :(得分:1)

这取决于“异常处理”的含义。

某些操作系统有异常机制 - 请参阅Windows exception handling routinesLinux signal handlers(其中一些是例外情况)。

如果你的意思是用户代码中的成语用来表示错误并解除堆栈清理任何已分配的对象,那么当堆栈被解开时,C代码不会在分配的对象上调用析构函数(它只是回收内存),所以函数返回状态值,并且调用代码在返回之前需要进行任何清理是正常的。

我不太了解Perl,但谷歌搜索“Perl异常处理”表明它有内置机制等同于try / catch和模块,它们提供“OO样式”异常处理。

答案 3 :(得分:1)

在C中有setjmp和longjump;实际上,setjmp()将当前上下文保存在堆栈中,而longjmp()可以将其展开回到setjmp()保存的点。关于这些的维基百科条目很好地填补了细节。

答案 4 :(得分:1)

在Perl中,像往常一样,有多种方法可以做到这一点。然而,开发者社区整体上已经确定了做大多数事情的正确方法。

我自己也成了Exception::Base的粉丝。

如果你想要更轻的实现,那么只需使用Carp。

使用eval { ... }; if ($@) { ... }构造捕获异常。

使用Exception :: Base,它提供了一种为您抽象出if ($@) { ... }构造的方法。您仍然需要使用eval { ... }

答案 5 :(得分:0)

传统方法是......嗯......不要:)

通常,人们只是在尝试某事后检查状态,如果出现问题,他们会清理并返回错误代码,而不是继续。这个错误检查和返回传播回函数调用堆栈,直到它返回到程序中的某个高级别,您需要通知用户而不是仅返回更多错误:

int try_it() {
  if (!do_something(...)) {
     return TRYIT_FAILURE;
  }
}

void my_gui() {
  rc = try_it()
  if (rc == TRYIT_FAILURE) {
    message_box("failed when trying it.", MB_ABORT|MB_RETRY);
  }
  ...
}

你也可以使用嵌套的ifs在一个大函数中执行此操作,如果你想要类似try ...除了construct之类的东西:

if (stage1()) {
   if (stage2()) {
       if(stage3()) {
           printf("success!\n");
       } else {
           // error handling for stage 3
       }
   } else {
       // error handling for stage 2
   }
} else { 
   // error handling for stage 1
}

如果你有点生气的话,你也可以用相同的方法做到这一点。

但是,你可以做到实际的异常,至少在C中。对于这种事情,C有两个标准的库调用:setjmp和longjmp。通过这些,您可以跳过几个函数调用到预定的位置,在那里您可以知道异常(跳转)。有关详情,请参阅Setjmp.h#exception_handling on wikipedia

似乎Perl确实有这样做的方法,虽然它对我来说远非直观。然后,我不用Perl编码:)

Perl FAQ Q4.8