4

这里有一篇关于跨应用程序控制流的有趣帖子。

好吧,最近,我遇到了一个有趣的问题。在潜在(实际上)无限递归序列中生成第 n 个值。这个特定的算法将在它成功的时候至少有 10-15 个堆栈引用深度。我的第一个想法是抛出一个看起来像这样(C#)的 SuccessException:

class SuccessException : Exception
{
    public string Value
    { get; set; }

    public SuccessException(string value)
        : base()
    {
        Value = value;
    }
}

然后做这样的事情:

try
{
    Walk_r(tree);
}
catch (SuccessException ex)
{
    result = ex.Value;
}

然后我的想法又回到了这里,我一遍又一遍地听到从不使用异常进行流量控制。有没有借口?如果你要实现它,你将如何构建这样的东西?

4

7 回答 7

5

在这种情况下,我将查看您的 Walk_r 方法,您应该有一些返回值的东西,抛出异常以指示成功,这不是一种常见的做法,并且至少会让任何看到代码的人感到非常困惑。更不用说与异常相关的开销了。

于 2008-10-06T14:22:46.150 回答
1

walk_r 应该在被击中时简单地返回值。这是一个非常标准的递归示例。我看到的唯一潜在问题是您说它可能是无穷无尽的,这必须在 walk_r 代码中通过保持递归深度的计数并停在某个最大值来补偿。

异常实际上使编码非常奇怪,因为方法调用现在抛出异常以返回值,而不是简单地返回“正常”。

try
{
    Walk_r(tree);
}
catch (SuccessException ex)
{
    result = ex.Value;
}

变成

result = Walk_r(tree);
于 2008-10-06T14:30:40.440 回答
1

我将在这里扮演魔鬼的拥护者并说坚持例外以表示成功。抛出/捕获可能很昂贵,但与搜索本身的成本相比可能微不足道,并且可能比提前退出该方法更容易混淆。

于 2008-10-06T15:00:06.963 回答
0

将异常作为算法的一部分抛出并不是一个好主意,尤其是在 .net 中。在某些语言/平台中,抛出异常时非常有效,例如,当可迭代对象耗尽时,它们通常是有效的。

于 2008-10-06T14:26:09.310 回答
0

为什么不只返回结果值?如果它返回任何东西,假设它是成功的。如果返回值失败,则表示循环失败。

如果您必须从失败中恢复过来,那么我建议您抛出异常。

于 2008-10-06T14:28:28.823 回答
0

使用异常的问题是 tey (在事物的宏伟计划中)非常低效和缓慢。在递归函数中使用 if 条件在需要时返回肯定会很容易。老实说,由于现代 PC 上的内存量不大(尽管并非不可能),您只需少量递归调用(<100)就会出现堆栈溢出。

如果堆栈是一个真正的问题,那么可能需要“创造性”并实施“深度限制搜索策略”,允许函数从递归返回并从最后一个(最深的)节点重新开始搜索。

总结一下:异常应该只在特殊情况下使用,我认为函数调用的成功不符合这样的条件。

于 2008-10-06T14:28:40.867 回答
0

在我的书中,在正常程序流中使用异常是有史以来最糟糕的做法之一。考虑一下可怜的 sap,他们正在寻找被吞下的异常,并且正在运行一个调试器,该调试器设置为在发生异常时停止。那家伙现在生气了……而且他有一把斧头。:P

于 2008-10-06T14:30:32.813 回答