【问题标题】:How to refactor this GOTO (no resource deallocation involved)?如何重构这个 GOTO(不涉及资源释放)?
【发布时间】:2011-11-07 19:41:09
【问题描述】:

这是一个简单的控制流 GOTO 问题,与资源分配无关。

检查一条数据是否“好”有两个级别。如果且仅当它通过第一次检查,我们进行第二次检查。如果数据未通过任一测试,我们将使用默认值。

第二次检查涉及到中间数据的几个步骤,所以我们不能把它放在短路的|| 条件下。此外,如果第二个测试通过,我们将使用第二个测试的输出而不是原始数据。

这是实时处理情况下的内循环,因此效率非常重要。我们不想多次进行任何计算。

if (firstCheck(data)) {
    result = analyze(data);
    if (secondCheck(result)) {
        use_result(result);
    }
    else {
        goto FAIL;
    }
}
else {
FAIL:
    use_result(DEFAULT_VALUE);
}

这个 GOTO 似乎以最大的效率满足了我的所有要求。我可以想到一些其他的方法来做到这一点,但所有这些都将涉及额外的存储或条件。不过,我对 GOTO 持谨慎态度。事实上,如果我使用它,这将是我第一次使用 GOTO。所以,请帮我找出路!

【问题讨论】:

    标签: optimization coding-style conditional goto control-flow


    【解决方案1】:

    使用continue 进入下一个循环迭代

    if (firstCheck(data)) {
        result = analyze(data);
        if (secondCheck(result)) {
            use_result(result);
            continue;
        }
    }
    use_result(DEFAULT_VALUE);
    

    【讨论】:

    • 有趣的是,两个答案都使用“技巧”来使其发挥作用:continue 基本上是受限制的goto,而 C 的“赋值是表达式”成语是 IMO 的一个 hack-provoking 语言功能。接受这个是因为它让我对analyze()secondCheck() 有更大的灵活性,但同时支持两者。
    【解决方案2】:

    好吧,我们可以不费吹灰之力地解决这个问题,但是以这种方式使用 goto 并不一定是不好的行为 - 例如linux内核也使用这种约定在一个地方进行错误处理,我认为代码很清楚。

    使用异常来解决这个问题显然是一种解决方案,但这在错误情况下确实具有成本效益,所以我认为这是不可能的。

    所以如果你愿意,这应该没问题:

    if (firstCheck(data) && secondCheck(result = analyze(data)) {
        use_result(result);
    }
    else {
        // fail
    }
    

    【讨论】:

    • use_result(result) 将失败,因为未定义结果。另外,OP 不想分析不止一次。
    • 哦,你是对的,最好解决这个问题。不过,我看不到我们不止一次分析的地方..
    • 现在你分析的不止一次,但我害怕use_result(analyze(data)) 没有在你当前的代码中使用。
    • 在哪里?我在那里只有一个要分析的调用,调用顺序与给定的相同:firstCheck,[analyze,secondCheck] 如果 firstCheck 为真,[use_result] 如果 secondCheck 为真。好的,如果第二个代码块大于一条语句,我们必须为第二个代码块使用一个函数,但使用一个内联函数,不会有任何损失。
    • 您可以通过创建一个异常子类来防止其堆栈跟踪被填充,或者只创建一次异常对象,缓存它,然后重复抛出缓存的异常。如果您将异常仅用于流控制,则无需关心堆栈跟踪。
    【解决方案3】:

    您不只是使用 goto。您正在使用进入另一个范围的 goto。简单得多:

    if (firstCheck(data)) {
        result = analyze(data);
        use_result (secondCheck (result) ? result : DEFAULT_VALUE);
    }
    else {
        use_result(DEFAULT_VALUE);
    }
    

    更简洁,无代码重复,可扩展:

    int result = DEFAULT_VALUE;
    if (firstCheck(data)) {
        int tmpResult = analyze(data);
        if (secondCheck (tmpResult))
            result = tmpResult;
    }
    use_result (result);
    

    【讨论】:

      猜你喜欢
      • 2013-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-09
      相关资源
      最近更新 更多