【问题标题】:May I use goto in such situation?我可以在这种情况下使用 goto 吗?
【发布时间】:2012-03-28 19:43:23
【问题描述】:

我想知道,如果在这种情况下使用 goto ok?你能提出更好的解决方案吗?我看到只有一个在 cicle 时获得第二个,但随后有必要调用“makeMove”两次。

void BoardView::startGame()
{
    int currStep=0;
    int x,y;
    while (board_->isWin()==none)
    {
        currStep++;
        show();
    wrong:
        std::cout << " Player " << (currStep%2==0 ? 1 : 2) << ": ";
        std::cin >> x;
        y=x%10;
        x/=10;
        if (!board_->makeMove(x,y,(currStep%2==0 ? cross : zero)))
        {
            std::cout << "Wrong move! Try again.\n";
            goto wrong;
        }
    }
}

【问题讨论】:

  • 一个循环或一个单独的函数。
  • @PlasmaHH 一个循环一个单独的函数。输入确实需要分解成一个单独的函数。
  • @JamesKanze:我没有使用异或:P
  • @karlphillip:该示例适用于 C。首选 RAII 用于在 C++ 中进行清理。
  • @Fippo 如果是为了自学,更重要的是做对了。

标签: c++ goto


【解决方案1】:

不要使用goto。成功移动后,使用while (true) 循环和break 循环。

while (true) {
    std::cout << " Player " << (currStep%2==0 ? 1 : 2) << ": ";
    std::cin >> x;
    y=x%10;
    x/=10;
    if (board_->makeMove(x,y,(currStep%2==0 ? cross : zero)))
        break;
    std::cout << "Wrong move! Try again.\n";
}

【讨论】:

  • 当然,这只是一个隐藏在另一个名字下的goto
  • @JamesKanze:是的,但是会跳转到范围的末尾而不是程序中的某个随机位置。此外,每个控制结构都是变相的goto。
  • 但这并没有纠正原来的问题,他试图在函数中做太多事情。
【解决方案2】:

也许:

void BoardView::startGame()
{
    int currStep=1;
    int x,y;
    show();
    while (board_->isWin()==none)
    {
        std::cout << " Player " << (currStep%2==0 ? 1 : 2) << ": ";
        std::cin >> x;
        y=x%10;
        x/=10;
        if (!board_->makeMove(x,y,(currStep%2==0 ? cross : zero)))
        {
            std::cout << "Wrong move! Try again.\n";
            continue;
        }
        ++currStep;
        show();
    }
}

不完全一样,但是没有使用goto。

【讨论】:

    【解决方案3】:

    是的,您可以进行这种跳转,但通常最好避免使用goto。例如,您可以像这样重写它:

    void BoardView::startGame()
    {
        int currStep=1;
        int x,y;
        show();
        while (board_->isWin()==none)
        {
            std::cout << " Player " << (currStep%2==0 ? 1 : 2) << ": ";
            std::cin >> x;
            y=x%10;
            x/=10;
            if (board_->makeMove(x,y,(currStep%2==0 ? cross : zero)))
            {
                currStep++;
                show();
            }
            else
            {
                std::cout << "Wrong move! Try again.\n";
            }
        }
    }
    

    【讨论】:

      【解决方案4】:

      一般建议是避免使用 GOTO 语句,但是,用 do while 查看修改后的代码

          void BoardView::startGame()
      {
          int currStep=0;
          int x,y;
          while (board_->isWin()==none) {
      
              currStep++;
              show();
              int retry = 0; /* So that 'retry' is visible to do while loop */ 
              do {
                    retry = 0;
                    std::cout << " Player " << (currStep%2==0 ? 1 : 2) << ": ";
                    std::cin >> x;
                    y=x%10;
                    x/=10;
                   if (!board_->makeMove(x,y,(currStep%2==0 ? cross : zero))) {
      
                      std::cout << "Wrong move! Try again.\n";
                      retry = 1
                   } 
      
             } while (retry);
          }
      }
      

      【讨论】:

        【解决方案5】:

        您应该尽可能避免 goto。仅在大型嵌套程序中使用时才使用。否则使用 goto 会使程序不可靠、不可读且难以调试。 goto 的另一个大问题是,当我们使用它们时,我们永远无法确定我们是如何到达代码中的某个点的。它们模糊了控制流。所以避开他们。

        我建议使用两个while循环……会更好……

        【讨论】:

          【解决方案6】:

          有什么问题:

          std::pair<int, int> BoardView::getNextMove()
          {
              std::cout << " Player " << (currStep & 2 == 0 ? 1 : 2) << ": ";
              int tmp;
              std::cin >> temp;
              return std::pair<int, int>( tmp / 10, tmp % 10 );
          }
          
          void BoardView::startGame() 
          {
              int currentStep = 0;
              while ( myBoard->isWin() == none ) {
                  std::pair<int, int> move = getNextMove();
                  while ( ! myBoard->makeMove( move, (currentStep % 2 == 0 ?  cross : zero) ) {
                      std::cout << "Wrong move! Try again" << std::endl;
                      move = getNextMove();
                  }
              }
          }
          

          (虽然我更喜欢 Move 类型的显式类,而不是 只是std::pair。成员 rowcolumn 更加明确 比firstsecond。)

          通常,如果您被 goto(甚至是 continuebreak),这是在单个函数中投入过多的症状。

          【讨论】:

          • 我认为你在意识形态上是对的。但是效率呢?使用pair,函数调用,返回值...
          • @Fippo 效率如何?代码太慢了吗?探查器是否显示这是瓶颈。在实践中,最有效的代码将是最封装的代码,因为一旦发现瓶颈,这将允许对算法和数据结构进行最彻底的更改。
          【解决方案7】:

          两个循环,没有常量条件表达式,只有一个 makeMove 调用:

          void BoardView::startGameLoop()
          {
              int currStep = 0;
              int x,y;
              while (none == board_->isWin())
              {
                  ++currStep;
                  show();
          
                  for (;;)
                  {
                      std::cout << " Player " << ((currStep & 1) + 1) << ": ";
                      std::cin >> x;
                      y = x % 10;
                      x /= 10;
                      if (!board_->makeMove(x, y, (currStep & 1) ? zero : cross))
                      {
                          std::cout << "Wrong move! Try again.\n";
                          continue;
                      }
                      break;
                  }
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2023-03-24
            • 2016-09-12
            • 2016-11-07
            • 2022-08-05
            • 2018-05-05
            • 1970-01-01
            • 2022-11-14
            相关资源
            最近更新 更多