Альтернативы C, такие как маркировка и экранирование вложенных циклов для C ++ - PullRequest
1 голос
/ 30 апреля 2019

В 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 ++ добавил лямбда-выражения / замыкания, которые потенциально позволили бы мне сделать это, но я не совсем уверен, как они будут работать в этом случае.

Использование try throw catch - наиболее близкая конструкция, которую я могу придумать, которая вызывает такое поведение.но неосторожность использования системы ошибок, когда ничего не нужно, беспокоит меня (они слышны медленно).

Я испытываю желание просто обернуть ее во внешний C, за исключением того, что я полностью полагаюсь на библиотеку c ++для всего проекта, так что это также кажется небрежным.

Является ли блок try или просто перезаписывает мои единственные опции?

Ответы [ 3 ]

3 голосов
/ 30 апреля 2019

Ни в C, ни в C ++ нет помеченного оператора break (вы, вероятно, используете расширение языка, а не стандартное C).

Вместо этого вы можете использовать goto для выхода из вложенного цикла.

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

Я смог использовать goto для решения этой проблемы ... Я думал, что это была запрещенная конструкция в c ++?

Нет.goto не «забанен» в C ++.

Это совершенно хороший способ использования goto.Не существует эквивалентного структурированного управляющего оператора.


lambdas / closures [...] потенциально позволили бы мне сделать это, но я не совсем уверен, как они будут работать в этомcase.

Если у вас аллергия на goto, тогда вы действительно можете использовать лямбду, но я не вижу в ней дополнительной читабельности:

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

Вместолямбда, вы можете использовать именованную функцию.Но в этом случае вам нужно передать любые переменные (такие как b, c и d) в качестве аргументов (при условии, что они не глобальные).


Еще один способ - этодополнительная переменная:

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

Из этих трех методов я рекомендую goto, поскольку он наиболее читабелен.За исключением случая, когда фактический внутренний цикл, опущенный в примере, очень длинный, в этом случае отдельная функция может быть лучше.

1 голос
/ 30 апреля 2019

Как уже указывалось другими, 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();
    …
}
0 голосов
/ 30 апреля 2019

Замена разрыва на goto здесь не рекомендуется. Могут быть проблемы с неправильным вызовом конструкторов и деструкторов. Хотя goto все еще существует в C ++, вы на самом деле не хотите использовать его, если вы действительно не знаете, что делаете! Более безопасный вариант - использовать блок try-catch. Лучшим подходом было бы перефакторинг вашего алгоритма (в настоящее время это O (N ^ 3), который действительно должен звонить в некоторые сигналы тревоги!)

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