Чи можливо за допомогою break
функції вийти з декількох вкладених for
циклів?
Якщо так, то як би ви зробили це робити? Чи можете ви також контролювати кількість циклів break
виходів?
Чи можливо за допомогою break
функції вийти з декількох вкладених for
циклів?
Якщо так, то як би ви зробили це робити? Чи можете ви також контролювати кількість циклів break
виходів?
Відповіді:
AFAIK, C ++ не підтримує цикли іменування, як це роблять Java та інші мови. Ви можете використовувати goto або створити значення прапора, яке ви використовуєте. В кінці кожного циклу перевірте значення прапора. Якщо встановлено значення true, ви можете вирватися з цієї ітерації.
goto
якщо це найкращий варіант.
goto
: погані програмісти та прагматичні програмісти. Перші пояснюють себе. Останні, до яких ви б вписалися, якщо вирішите добре їх використовувати, використовуйте так звану концепцію "зла", коли вона менша з (двох) злих. Прочитайте це, щоб краще зрозуміти деякі поняття C ++, які, можливо, вам доведеться час від часу використовувати (макроси, goto, препроцесор, масиви): parashift.com/c++-faq-lite/big-picture.html#faq-6.15
goto
рідко коли-небудь є найкращим варіантом. Чому б не ввести петлі у власну функцію ( inline
якщо вас турбує швидкість) і return
з цього?
Ні, не псуйте це з break
. Це останній оплот для використання goto
.
Просто, щоб додати явну відповідь за допомогою лямбда:
for (int i = 0; i < n1; ++i) {
[&] {
for (int j = 0; j < n2; ++j) {
for (int k = 0; k < n3; ++k) {
return; // yay we're breaking out of 2 loops here
}
}
}();
}
Звичайно, ця модель має певні обмеження, і, очевидно, лише C ++ 11, але я думаю, що це досить корисно.
Інший підхід до виходу з вкладеного циклу полягає в розподілі обох циклів на окрему функцію, а також return
із цієї функції, коли потрібно вийти.
Звичайно, це підводить інший аргумент того, чи слід коли-небудь явно return
виконувати функції з будь-якої іншої точки, ніж в кінці.
continue_processing
), які контролювали виконання блоків коду далі внизу функції.
Розрив буде виходити лише з внутрішньої петлі, що містить його.
Ви можете використовувати goto для виходу з будь-якої кількості петель.
Звичайно, гото часто вважається шкідливим .
чи правильно використовувати функцію перерви [...]?
Використання перерви та переходу може ускладнити міркування про правильність програми. Дивіться тут дискусію з цього приводу: Дейкстра не був божевільним .
break
або return
.
break
і return
мати перевагу перед тим, goto
що вам не потрібно полювати на етикетку, щоб знайти, куди вони йдуть. Так, під ними вони є якимись goto
, але дуже обмеженими. Їх набагато простіше розшифрувати за допомогою мозку програміста, що відповідає зразкам, ніж необмежений goto
. Тож ІМО вони переважніші.
goto
.
Хоча ця одяг вже була представлена, я думаю, що хорошим підходом є наступне:
for(unsigned int z = 0; z < z_max; z++)
{
bool gotoMainLoop = false;
for(unsigned int y = 0; y < y_max && !gotoMainLoop; y++)
{
for(unsigned int x = 0; x < x_max && !gotoMainLoop; x++)
{
//do your stuff
if(condition)
gotoMainLoop = true;
}
}
}
gotoMainLoop
перевіряється кожен цикл
goto
робить ядро більш читабельним та більш ефективним.
Як щодо цього?
for(unsigned int i=0; i < 50; i++)
{
for(unsigned int j=0; j < 50; j++)
{
for(unsigned int k=0; k < 50; k++)
{
//Some statement
if (condition)
{
j=50;
k=50;
}
}
}
}
Приклад коду за допомогою goto
та мітки для виходу із вкладеного циклу:
for (;;)
for (;;)
goto theEnd;
theEnd:
Один з приємних способів вирватися з декількох вкладених циклів - це переробити код у функцію:
void foo()
{
for(unsigned int i=0; i < 50; i++)
{
for(unsigned int j=0; j < 50; j++)
{
for(unsigned int k=0; k < 50; k++)
{
// If condition is true
return;
}
}
}
}
goto може бути дуже корисним для розбиття вкладених циклів
for (i = 0; i < 1000; i++) {
for (j = 0; j < 1000; j++) {
for (k = 0; k < 1000; k++) {
for (l = 0; l < 1000; l++){
....
if (condition)
goto break_me_here;
....
}
}
}
}
break_me_here:
// Statements to be executed after code breaks at if condition
Я думаю, що goto
є дійсним у цій обставині:
Для імітації a break
/ continue
, потрібно:
for ( ; ; ) {
for ( ; ; ) {
/*Code here*/
if (condition) {
goto theEnd;
}
}
}
theEnd:
for ( ; ; ) {
for ( ; ; ) {
/*Code here*/
if (condition) {
i++;
goto multiCont;
}
}
multiCont:
}
i
. Звідси i++
перед
Інші мови, такі як PHP, приймають параметр break (тобто перерва 2;), щоб вказати кількість вкладених рівнів циклу, з яких ви хочете вийти, C ++, однак, не робить. Вам доведеться розробити це, використовуючи булевий сигнал, який ви встановили на помилкове перед циклом, встановлене на істинному циклі, якщо ви хочете перервати, плюс умовний перерву після вкладеного циклу, перевіривши, чи встановлено булеве значення true і зламати, якщо так.
Я знаю, що це стара посада. Але я б запропонував трохи логічну та простішу відповідь.
for(unsigned int i=0; i < 50; i++)
{
for(unsigned int j=0; j < conditionj; j++)
{
for(unsigned int k=0; k< conditionk ; k++)
{
// If condition is true
j= conditionj;
break;
}
}
}
j = conditionj
не вийде, якщо у вас замість нього складний предикат j < conditionj
.
Розбийте будь-яку кількість циклів лише на одну bool
змінну, див. Нижче:
bool check = true;
for (unsigned int i = 0; i < 50; i++)
{
for (unsigned int j = 0; j < 50; j++)
{
for (unsigned int k = 0; k < 50; k++)
{
//Some statement
if (condition)
{
check = false;
break;
}
}
if (!check)
{
break;
}
}
if (!check)
{
break;
}
}
У цьому коді ми break;
всі петлі.
Я не впевнений, чи варто того, але ви можете імітувати циклічні імена Java за допомогою декількох простих макросів:
#define LOOP_NAME(name) \
if ([[maybe_unused]] constexpr bool _namedloop_InvalidBreakOrContinue = false) \
{ \
[[maybe_unused]] CAT(_namedloop_break_,name): break; \
[[maybe_unused]] CAT(_namedloop_continue_,name): continue; \
} \
else
#define BREAK(name) goto CAT(_namedloop_break_,name)
#define CONTINUE(name) goto CAT(_namedloop_continue_,name)
#define CAT(x,y) CAT_(x,y)
#define CAT_(x,y) x##y
Приклад використання:
#include <iostream>
int main()
{
// Prints:
// 0 0
// 0 1
// 0 2
// 1 0
// 1 1
for (int i = 0; i < 3; i++) LOOP_NAME(foo)
{
for (int j = 0; j < 3; j++)
{
std::cout << i << ' ' << j << '\n';
if (i == 1 && j == 1)
BREAK(foo);
}
}
}
Ще один приклад:
#include <iostream>
int main()
{
// Prints:
// 0
// 1
// 0
// 1
// 0
// 1
int count = 3;
do LOOP_NAME(foo)
{
for (int j = 0; j < 3; j++)
{
std::cout << ' ' << j << '\n';
if (j == 1)
CONTINUE(foo);
}
}
while(count-- > 1);
}
Ви можете використовувати спробувати ... ловить.
try {
for(int i=0; i<10; ++i) {
for(int j=0; j<10; ++j) {
if(i*j == 42)
throw 0; // this is something like "break 2"
}
}
}
catch(int e) {} // just do nothing
// just continue with other code
Якщо вам доведеться вирватися з декількох циклів одночасно, це все одно є винятком.
Вихід із циклу for-циклу для мене трохи дивний, оскільки семантика for-loop зазвичай вказує на те, що він буде виконаний задану кількість разів. Однак це не погано у всіх випадках; якщо ви шукаєте щось у колекції і хочете зламати, коли знайдете, це корисно. Виривання вкладених циклів, однак, неможливо в C ++; це в інших мовах через використання міченої перерви. Можна використовувати етикетку та гото, але це може спричинити печію вночі ..? Схоже, найкращий варіант.