【问题标题】:How to avoid using multiple if-else to check whether the returned value is an error code?如何避免使用多个 if-else 检查返回值是否为错误码?
【发布时间】:2019-09-07 04:06:01
【问题描述】:

我使用错误代码作为返回值。但是每次调用函数时,我都会使用 if-else 来检查返回值是否良好。 例如,

int v1,v2,v3,v4;
v1 = func1();
if(v1 != OK){
    // do somethings
}
else{
    v2 = func2();
    if(v2!=OK){
        // do somethings
    }
    else{
        v3 = func3();
        if(v3!=OK){
            // do somethings
        }
        else{
        v4 = func4();
           if(v4!=OK){
               // do somethings
           }
           else{
               .....
           }
        }
    }
}

【问题讨论】:

  • 您可以使用例外。不过它仍然需要多个块。
  • 如果你真的需要这么多嵌套的东西,可能存在一些逻辑设计缺陷......
  • if(func1() != OK) { /* do something */...; return; }。之后你就不需要else。如果之后有一些代码,您可能需要将其移动到函数中(以便return 正常工作)。

标签: c++


【解决方案1】:

您可以将代码包装到另一个函数中以避免嵌套 if-else 块。

void foo() {

    int v = func1();
    if (v != OK) {
        // do somethings
        return;
    }

    v = func2();
    if (v != OK) {
        // do somethings
        return;
    }

    v = func3();
    if (v != OK) {
        // do somethings
        return;
    }

    v = func4();
    if (v != OK) {
        // do somethings
        return;
    }

    .....

}

【讨论】:

    【解决方案2】:

    这是我在不存在 C++ 异常时使用的一些模式。在所有情况下,目的是在代码中有一个返回点。 (因为单点返回通常会使代码更具可读性和可维护性 - 并非总是如此,但努力争取是一件好事。)此外,当您利用 RAII 时,所有解决方案都很棒(让局部变量的析构函数为您完成所有清理工作)。

    经典方法是“三角形模式”:

    int MyCode()
    {
        int v1, v2, v3, v4;
        int result = FAIL;
    
        v1 = func1();
        if (v1 == OK)
        {
           v2 = func2();
           if (v2 == OK)
           {
               v3 = func3();
               if (v3 == OK)
               {
                   v4 = func4();
                   if (v4 == OK)
                   {
                      result = OK;
                   }
                   else
                   {
                      // handle func4 failure
                   }
               }
               else
               {
                   // handle func3 failure
               }
           }
           else
           {
               // handle func2 failure
           }
        else
        {
            // handle func1 failure
        }
    
        if (result != OK)
        {
            // general cleanup
        }
    }
    

    对于上述情况,如果您可以利用 RAII 或将大部分“句柄清理代码”放在最后的 // general cleanup 块中,则不必在每个嵌套的 else 子句中编写冗余代码- 可能完全排除 else 子句。

    另一个我喜欢使用的变体是“链式成功检查”:

    int MyCode()
    {
        int result = OK;
    
        result = func1();
        if (result == OK)
        {
           // additional code to handle result of func1 before invoking func2
           result = func2();
        }
    
        if (result == OK)
        {
           // additional code to handle result of func2 before invoking func3
           result = func3();
        }
        else
        {
            // special error handling for func3 failing
        }
    
        if (result == OK)
        {
            result = func4();
        }
    
        if (result == OK)
        {
           // handle success case, if anything            
        }
        else
        {
            // general error handling and function cleanup goes here
        }
        return result;
    }
    

    一开始看起来很奇怪,但是当您以上述风格编写代码时,它可以让您看到代码的预期流程(当成功是常态时)。您可能会观察到,当发生错误情况时,对result==OK 进行了大量冗余检查。在发布版本中,编译器可以对此进行优化。

    链式成功检查的另一种变体是使用……等待它……不要惊慌……goto 宏专门用于跳转到函数的末尾(人群喘气)失败。但是看看它使代码看起来多么简单:

    #define JUMP_ON_ERROR(expr) {result = (expr); if (result != OK) goto Cleanup;}
    
    int MyCode()
    {
        int result = OK;
    
        JUMP_ON_ERROR(func1());
        JUMP_ON_ERROR(func2());
        JUMP_ON_ERROR(func3());
        JUMP_ON_ERROR(func4());
    Cleanup:
    
         if (result == OK)
         {
             // handle success
         }
         else
         {
             // handle failure
         }
         return result;
    }
    

    【讨论】:

      【解决方案3】:

      考虑在你的函数中使用 try catch 块并抛出异常,而不是返回错误值

      int v1, v2, v3, v4;
      try
      {
          v1 = func1();
          v2 = func2();
          v3 = func3();
          v4 = func4();
      }
      catch (Func1Exception e)
      {
          //handle Func1Exception
      }
      catch (Func2Exception e)
      {
          //handle Func2Exception
      }
      catch (Func3Exception e)
      {
          //handle Func3Exception
      }
      catch (Func4Exception e)
      {
          //handle Func4Exception
      }
      

      thisthis

      【讨论】:

        【解决方案4】:

        如果原型相同,您可以使用循环:

         using f_ptr = int (*)();
         using error_f_ptr = void (*)();
         std::pair<f_ptr, error_f_ptr> funcs[] = {
             {&func1, &err1},
             {&func2, &err2},
             {&func3, &err3},
             {&func4, &err4}
         };
        
         for (const auto& p : funcs) {
              const int v = p.first();
        
              if (v != OK) {
                  p.second();
                  return FAIL;
              }
         }
         return OK;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多