C 的替代方案,例如为 C++ 标记和转义嵌套循环

Alternitives to C like labling and escaping nested loops for C++

在 C 和 javascript 中,我喜欢编写这种东西的能力,并且让它正常工作。

while (a)
{
ctx: while(b)
     {
         while (c)
         {
             if(d) break ctx;
             ...
         }
     }
     ...
}

也许我只是对 C++ 版本感到困惑,但我在 g++ 中遇到了这种错误:

error: expected ‘;’ before ‘ctx’
     break ctx;
error: ‘ctx’ was not declared in this scope
warning: label ‘ctx’ defined but not used [-Wunused-label]
 ctx:

C++ 似乎拒绝让我编写此代码。 C++ 添加了 lambdas/closures 可能会让我这样做,但我不太确定它们在这种情况下如何工作。

使用 try throw catch 是我能想到的最接近的构造,它会产生这种行为,但是当需要 none 时使用错误系统的草率让我担心(而且我听说它们很慢)。

我很想将它包装在 extern C 中,除非我在整个项目中完全依赖 C++ 库,所以这也让人感到草率。

是 try 块还是只是重写我唯一的选项?

C 和 C++ 都没有带标签的 break 语句(您可能使用的是语言扩展,而不是标准 C)。

相反,您可以使用 goto 来跳出嵌套循环。

while (a)
{
    while(b)
    {
        while (c)
        {
            if(d)
                goto break_b;
        }
    }
    break_b:
    // ...
}

I was able to use goto to solve this... I though it was a banned construct in c++?

没有。 goto 在 C++ 中不是 "banned"。

这是使用 goto 的完美方式。不存在等效的结构化控制语句。


lambdas/closures [...] potentially would let me do this but I'm not quite sure how they would work in this case.

如果您对 goto 过敏,那么您确实可以使用 lambda,但我认为它不会提供任何额外的可读性:

while (a)
{
    [&](){
        while(b)
        {
            while (c)
            {
                if(d)
                    return;
            }
        }
    }();
    // ...
}

您可以使用命名函数来代替 lambda。但在那种情况下,您需要将任何变量(例如 bcd)作为参数传递(假设它们不是全局变量)。


另一种方法是一个额外的变量:

while (a)
{
    bool break_b = false;
    while(b)
    {
        while (c)
        {
            if(d) {
                break_b = true;
                break;
            }
        }
        if (break_b)
            break;
    }
    // ...
}

在这三种方法中,我推荐 goto,因为它的可读性最高。除非示例中省略的实际内部循环非常长,在这种情况下,单独的函数可能会更好。

这里不建议用 goto 代替 break。可能存在构造函数和析构函数未被正确调用的问题。虽然 goto 仍然存在于 C++ 中,但除非您 真的 知道自己在做什么,否则您真的不想使用它!一个更安全的选择是使用 try-catch 块。更好的方法是重构你的算法 (目前它是 O(N^3),这真的应该敲响警钟!)

while (a)
{
  try
  {
    while(b)
    {
      while (c)
      {
        if(d) throw;
      }
    }
  }
  catch(...)
  {
  }
}

正如其他人已经指出的那样,goto 将是一种完全满足您要求的方法。

话虽这么说,但我认为,在问如何突破极其复杂的控制流结构这个问题之前,您应该首先问问自己,为什么要从一个极其复杂的流结构开始。这些循环中发生了什么?难道不应该将每个循环中发生的事情移到它自己的函数中吗?例如,而不是

while (a)
{
ctx: while (b)
     {
         while (c)
         {
             if (d) goto ctx;
             …
         }
     }
     …
}

为什么不

bool doC()
{
    while (c)
    {
        if (d)
            return false;
        …
    }

    return true;
}

void doB()
{
    while (b && doC());
}

然后

while (a)
{
    doB();
    …
}