Чи можливо за допомогою 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 ++; це в інших мовах через використання міченої перерви. Можна використовувати етикетку та гото, але це може спричинити печію вночі ..? Схоже, найкращий варіант.