A.1.12 Oct-Files中的异常与错误处理

Octave的另一个重要特性是其能够在长时间计算过程中响应用户键入的 Control-C。该能力基于C++异常处理机制,当异常被处理时,由C++ new/delete方法分配的内存会被自动释放。在编写可能长时间运行的oct-file时,程序员必须定期使用宏 OCTAVE_QUIT,以允许Octave检查并可能响应用户键入的Control-C。例如:

for (octave_idx_type i = 0; i < a.nelem (); i++)
  {
    OCTAVE_QUIT;
    b.elem (i) = 2. * a.elem (i);
  }

在内层循环中使用OCTAVE_QUIT 宏,使得Octave能够检测并响应Control-C按键序列。如果没有这个宏,用户必须等待oct-file函数返回后中断才会被处理,或者用户必须连续按三次Control-C,这会强制Octave完全退出。

OCTAVE_QUIT 宏确实会带来非常小的性能开销; 对于已知循环次数很少的情况,使用OCTAVE_QUIT可能没有意义。

当创建使用外部库的oct-file时,函数可能会在外部库中花费大量时间。在这种情况下,通常无法使用OCTAVE_QUIT 宏。针对此情况的替代代码如下:

BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
... 一些调用"外部"函数的代码 ...
END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;

这样做的缺点是,如果外部代码在内部分配了任何内存,那么这些内存可能会在中断期间丢失而无法被释放。因此,理想情况下,Octave本身应使用rwdata方法或OCTAVE_LOCAL_BUFFER 宏来分配外部代码所需的所有内存。

Octave的unwind_protect机制 (参见unwind_protect 语句)也可以用在oct-file中。它与Octave的异常处理机制相结合,确保即使在发生异常时,某些恢复代码也始终会被执行。以下是一个使用此机制的示例:

#include <octave/oct.h>
#include <octave/unwind-prot.h>

void
my_err_handler (const char *fmt, ...)
{
  // 什么都不做!!
}

void
my_err_with_id_handler (const char *id, const char *fmt, ...)
{
  // 什么都不做!!
}

DEFUN_DLD (unwinddemo, args, nargout, "Unwind Demo")
{
  if (args.length () < 2)
    print_usage ();

  NDArray a = args(0).array_value ();
  NDArray b = args(1).array_value ();

  // 创建 unwind_action 对象。在封闭作用域结束时,
  // 这些对象的析构函数将使用指定的参数调用给定的函数。

  octave::unwind_action restore_warning_handler
    (set_liboctave_warning_handler, current_liboctave_warning_handler);

  octave::unwind_action restore_warning_with_id_handler
    (set_liboctave_warning_with_id_handler,
     current_liboctave_warning_with_id_handler);

  set_liboctave_warning_handler (my_err_handler);
  set_liboctave_warning_with_id_handler (my_err_with_id_handler);

  return octave_value (quotient (a, b));
}

从示例中可以看出:

unwinddemo (1, 0)
⇒  Inf
1 / 0
⇒  warning: division by zero
   Inf

unwinddemo函数中,除零警告(实际上包括所有警告)都被禁用了。


版权所有 © 2024-2026 Octave中文网

ICP备案/许可证号:黑ICP备2024030411号-4