【问题标题】:goto statement usage in C++C++ 中的 goto 语句用法
【发布时间】:2014-01-17 15:13:23
【问题描述】:

我有一个funcA,我每毫秒调用一次。另一个funcB。我想使用 goto 语句。但是当我看流程时(当m_tempdata不是NULL时),打印"stage 2"之后,也是打印"cleanup starts"。通常,我希望在打印"stage 2" 后返回下一轮。我错了吗?

void ClassA::funcA()
{
    m_tempdata = m_freedata;

    printf("stage 1 \n");

    if (NULL == m_tempdata)
    {
        printf("going cleaning \n" );
        goto cleanup;
    }
    m_freedata = m_tempdata->next;

    printf("stage 2 \n");

cleanup: printf("cleanup starts \n");
    // ... some additional work todo
}

【问题讨论】:

  • 您为什么希望它返回? cleanup: 只是您的陈述之间的标签。此外,这里没有充分的理由证明goto 的合理性:v
  • 种下什么就收什么
  • 这应该很有趣...

标签: c++ goto


【解决方案1】:

通常情况下,我希望在下一个打印“阶段 2”后返回 转动。我错了吗?

是的,你错了

在标签没有跳转到的情况下,代码将直接跳转到它并继续。标签不是指令。它不会导致程序神奇地返回或跳转到其他地方。

这里有一个更好的写法:

void ClassA::funcA()
{
  m_tempdata = m_freedata;

  printf("stage 1 \n");

  if (NULL == m_tempdata)
  {
    printf("going cleaning \n" );
    Cleanup();
    return;
  }

  m_freedata = m_tempdata->next;
}

void ClassA::Cleanup()
{
  printf("cleanup starts \n");
  //      ... some additional work todo
}

请不要使用goto。它使代码更难理解、调试和维护。另外,您最终会像这里一样犯下愚蠢的错误,因为您之前做出了糟糕的设计决策。请改用现代流量控制结构。

【讨论】:

    【解决方案2】:

    您似乎没有充分/令人信服的理由在此代码中使用 goto,所以不要。使用更易读的控制流结构。

    printf("stage 1\n");
    if (NULL != m_tempdata)
    {
        printf("stage 2\n");
        // ...
    }
    else
    {
        printf("cleanup starts\n");
        // ...
    }
    

    如果无论“第 2 阶段”是否运行都需要进行清理,请删除 else 块并将清理代码放在最后。

    【讨论】:

      【解决方案3】:

      为什么要停止?没有什么可以中断语句printf("stage 2 \n"); 和语句printf("cleanup starts \n");(恰好标记为cleanup:)之间的控制流。

      如果您真的希望它中断,则必须在 cleanup: 标签之前插入 return 语句。

      但是,请认真重新考虑使用goto。它使程序很难推理 - 总是更喜欢结构化流程(ifs、循环、函数调用)。

      【讨论】:

        【解决方案4】:

        没有什么可以告诉编译器函数应该在“阶段 2”之后退出。如果您希望它返回,您必须通过添加 return 语句来实际告诉编译器。

        【讨论】:

        • 实际上,由于清理是由 goto 语句调用的,我以为只有在调用 goto 时才会执行。是否可以让它工作而不返回?
        • @AvbAvb 您仍然可以使用 return 而不使用表达式:return;。它将在return 语句处从函数返回(有或没有返回值)。
        【解决方案5】:

        我怀疑您正在尝试使用像这样的老式 C 编程模式:

        void do_hot_stuff (void)
        {
            void * data1 = malloc (123);
            if (data1 == NULL) goto fail1;
        
            void * data2 = malloc (123);
            if (data2 == NULL) goto fail2;
        
            void * data3 = malloc (123);
            if (data3 == NULL) goto fail3;
        
            // do your hot stuff here
        
            free (data3);
            fail3:
            free(data2);
            fail2:
            free(data1);
            fail1:
        }
        

        坦率地说,自从我上次为我的 Amiga 编写代码是在 80 年代后期以来,我并没有使用过这个。
        只是不要。

        【讨论】:

        • 我认为你把标签和最后的陈述搞混了 :) 你可能仍然可以在 OpenSSL 等库中找到这类东西,但我当然希望人们不要继续写这样的代码。几年前,我看到一些生产代码,其中大多数函数都包含一个巨大的 while 循环,该循环包装了“热门内容”以捕获异常情况。讨厌的东西,但仍然比goto 好:)
        • @MihaiTodor Mmmm... 我认为语句放置是可以的(如果您无法分配 data3,则只需释放 data2 和 data1),但无论如何这对博物馆来说是件好事。跨度>
        • 啊,对 :)) 另一个从不使用此类东西的好例子 :)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-27
        • 1970-01-01
        相关资源
        最近更新 更多