Przerwa
Chociaż widziałeś już break stwierdzenie w kontekście switch oświadczenia (8.5 - Podstawy instrukcji Switch), zasługuje ono na pełniejsze potraktowanie, ponieważ można go również używać z innymi typami instrukcji przepływu sterowania. Instrukcja break powoduje zakończenie pętli while, pętli do-while, pętli for lub instrukcji switch, a wykonanie jest kontynuowane od następnej instrukcji po przerwaniu pętli lub przełącznika.
Przerywanie przełącznika
W kontekście instrukcji switch na końcu instrukcji zwykle używane jest break każdego przypadku, aby oznaczyć, że sprawa została zakończona (co zapobiega przejściu do kolejnych przypadków):
#include <iostream>
void printMath(int x, int y, char ch)
{
switch (ch)
{
case '+':
std::cout << x << " + " << y << " = " << x + y << '\n';
break; // don't fall-through to next case
case '-':
std::cout << x << " - " << y << " = " << x - y << '\n';
break; // don't fall-through to next case
case '*':
std::cout << x << " * " << y << " = " << x * y << '\n';
break; // don't fall-through to next case
case '/':
std::cout << x << " / " << y << " = " << x / y << '\n';
break;
}
}
int main()
{
printMath(2, 3, '+');
return 0;
}Zobacz lekcję 8.6 -- Przełącz awarię i zakres aby uzyskać więcej informacji na temat awarii wraz z kilkoma dodatkowymi przykładami.
Przerywanie pętli
W kontekście pętli można zastosować instrukcję break używane do wcześniejszego zakończenia pętli. Wykonanie jest kontynuowane od następnej instrukcji po zakończeniu pętli.
Na przykład:
#include <iostream>
int main()
{
int sum{ 0 };
// Allow the user to enter up to 10 numbers
for (int count{ 0 }; count < 10; ++count)
{
std::cout << "Enter a number to add, or 0 to exit: ";
int num{};
std::cin >> num;
// exit loop if user enters 0
if (num == 0)
break; // exit the loop now
// otherwise add number to our sum
sum += num;
}
// execution will continue here after the break
std::cout << "The sum of all the numbers you entered is: " << sum << '\n';
return 0;
}Program ten pozwala użytkownikowi wpisać do 10 liczb i wyświetla sumę wszystkich wprowadzonych na końcu liczb. Jeśli użytkownik wprowadzi 0, przerwa spowoduje wcześniejsze zakończenie pętli (przed wprowadzeniem 10 liczb).
Oto przykładowe wykonanie powyższego programu:
Enter a number to add, or 0 to exit: 5 Enter a number to add, or 0 to exit: 2 Enter a number to add, or 0 to exit: 1 Enter a number to add, or 0 to exit: 0 The sum of all the numbers you entered is: 8
A break jest również powszechnym sposobem wyjścia z zamierzonej nieskończonej pętli:
#include <iostream>
int main()
{
while (true) // infinite loop
{
std::cout << "Enter 0 to exit or any other integer to continue: ";
int num{};
std::cin >> num;
// exit loop if user enters 0
if (num == 0)
break;
}
std::cout << "We're out!\n";
return 0;
}Przykładowe uruchomienie powyższego programu:
Enter 0 to exit or any other integer to continue: 5 Enter 0 to exit or any other integer to continue: 3 Enter 0 to exit or any other integer to continue: 0 We're out!
Przerwa vs powrót
Nowi programiści czasami mają problemy ze zrozumieniem różnicy pomiędzy instrukcją break i return. A break kończy przełącznik lub pętlę, a wykonanie jest kontynuowane od pierwszej instrukcji poza przełącznikiem lub pętlą. Instrukcja return kończy całą funkcję, w której znajduje się pętla, a wykonywanie jest kontynuowane w miejscu, w którym funkcja została wywołana.
#include <iostream>
int breakOrReturn()
{
while (true) // infinite loop
{
std::cout << "Enter 'b' to break or 'r' to return: ";
char ch{};
std::cin >> ch;
if (ch == 'b')
break; // execution will continue at the first statement beyond the loop
if (ch == 'r')
return 1; // return will cause the function to immediately return to the caller (in this case, main())
}
// breaking the loop causes execution to resume here
std::cout << "We broke out of the loop\n";
return 0;
}
int main()
{
int returnValue{ breakOrReturn() };
std::cout << "Function breakOrReturn returned " << returnValue << '\n';
return 0;
}Oto dwa uruchomienia tego programu:
Enter 'b' to break or 'r' to return: r Function breakOrReturn returned 1
Enter 'b' to break or 'r' to return: b We broke out of the loop Function breakOrReturn returned 0
Continue
Klasa Instrukcjacontinue zapewnia wygodny sposób zakończenia bieżącej iteracji pętli bez przerywania całej pętla.
Oto przykład użyciacontinue:
#include <iostream>
int main()
{
for (int count{ 0 }; count < 10; ++count)
{
// if the number is divisible by 4, skip this iteration
if ((count % 4) == 0)
continue; // go to next iteration
// If the number is not divisible by 4, keep going
std::cout << count << '\n';
// The continue statement jumps to here
}
return 0;
}Ten program wypisuje wszystkie liczby od 0 do 9, które nie są podzielne przez 4:
1 2 3 5 6 7 9
A continue Instrukcja działa w ten sposób, że bieżący punkt wykonania przeskakuje na sam dół bieżącej pętli.
W przypadku pętli for, instrukcja końcowa pętli for (w powyższym przykładzie przykład ++count) nadal jest wykonywany po kontynuacji (ponieważ dzieje się to po zakończeniu treści pętli).
Zachowaj ostrożność podczas używania instrukcji continue w pętlach while lub do-while. Pętle te zazwyczaj zmieniają wartość zmiennych używanych w warunku wewnątrz treści pętli. Jeśli użycie instrukcji continue spowoduje pominięcie tych linii, wówczas pętla może stać się nieskończona!
Rozważ następujący program:
#include <iostream>
int main()
{
int count{ 0 };
while (count < 10)
{
if (count == 5)
continue; // jump to end of loop body
std::cout << count << '\n';
++count; // this statement is never executed after count reaches 5
// The continue statement jumps to here
}
return 0;
}Ten program ma za zadanie wypisać każdą liczbę od 0 do 9 z wyjątkiem 5. Ale w rzeczywistości wypisuje:
0 1 2 3 4
a następnie przechodzi w nieskończoną pętlę. Gdy count Jest 5, instrukcja if daje w wyniku true, a continue powoduje, że wykonanie przeskakuje na sam dół pętli. Zmienna count nigdy nie jest zwiększana. W rezultacie w następnym przebiegu count jest nadal 5, instrukcja if jest nadal true, a program kontynuuje pętlę w nieskończoność.
Oczywiście już wiesz, że jeśli masz oczywistą zmienną licznikową, powinieneś użyć pętli for , a nie while lub do while pętla.
Debata na temat użycia przerwania i kontynuowania
Wiele podręczników ostrzega czytelników, aby nie używali break i continue w pętlach, zarówno dlatego, że powoduje to przeskakiwanie przepływu wykonywania, jak i dlatego, że może utrudnić śledzenie przepływu logiki. Na przykład break w środku skomplikowanego fragmentu logiki może zostać pominięty lub może nie być oczywiste, w jakich warunkach powinien zostać wywołany.
Jednakże stosowane rozsądnie break i continue może sprawić, że pętle będą bardziej czytelne, zmniejszając liczbę zagnieżdżonych bloków i zmniejszając potrzebę stosowania skomplikowanej logiki pętli.
Rozważmy na przykład następujący program:
#include <iostream>
int main()
{
int count{ 0 }; // count how many times the loop iterates
bool keepLooping { true }; // controls whether the loop ends or not
while (keepLooping)
{
std::cout << "Enter 'e' to exit this loop or any other character to continue: ";
char ch{};
std::cin >> ch;
if (ch == 'e')
keepLooping = false;
else
{
++count;
std::cout << "We've iterated " << count << " times\n";
}
}
return 0;
}To program używa zmiennej logicznej do kontrolowania kontynuacji pętli, a także zagnieżdżonego bloku, który jest uruchamiany tylko wtedy, gdy użytkownik nie zakończy działania.
Oto wersja łatwiejsza do zrozumienia dzięki zastosowaniu break instrukcji:
#include <iostream>
int main()
{
int count{ 0 }; // count how many times the loop iterates
while (true) // loop until user terminates
{
std::cout << "Enter 'e' to exit this loop or any other character to continue: ";
char ch{};
std::cin >> ch;
if (ch == 'e')
break;
++count;
std::cout << "We've iterated " << count << " times\n";
}
return 0;
}W tej wersji, używając pojedynczej break instrukcji, uniknęliśmy użycia zmiennej logicznej (i konieczności zrozumienia zarówno jej zamierzonego zastosowania, i gdzie zmienia się jej wartość), instrukcja else i zagnieżdżony blok.Instrukcja
Klasa continue jest najskuteczniej używana na początku pętli for, aby pominąć iteracje pętli, gdy spełniony jest jakiś warunek. Dzięki temu możemy uniknąć zagnieżdżonych bloków.
Na przykład zamiast tego:
#include <iostream>
int main()
{
for (int count{ 0 }; count < 10; ++count)
{
// if the number is not divisible by 4...
if ((count % 4) != 0) // nested block
{
// Print the number
std::cout << count << '\n';
}
}
return 0;
}Możemy napisać tak:
#include <iostream>
int main()
{
for (int count{ 0 }; count < 10; ++count)
{
// if the number is divisible by 4, skip this iteration
if ((count % 4) == 0)
continue;
// no nested block needed
std::cout << count << '\n';
}
return 0;
}Minimalizacja liczby używanych zmiennych i utrzymywanie małej liczby zagnieżdżonych bloków poprawiają zrozumiałość kodu bardziej niż break lub continue szkodzą. Z tego powodu uważamy, że rozsądne użycie break lub continue jest dopuszczalne.
Najlepsza praktyka
Użyj break icontinue, gdy upraszczają one logikę pętli.
Debata na temat stosowania wczesnych zwrotów
Istnieje podobny argument, który można wysunąć w przypadku instrukcji return. Instrukcja return, która nie jest ostatnią instrukcją w funkcji, nazywana jest wczesnym powrotem. Wielu programistów uważa, że należy unikać wczesnych powrotów. Funkcja, która ma tylko jedną instrukcję return na dole, jest prosta — można założyć, że funkcja przyjmie swoje argumenty, wykona dowolną zaimplementowaną logikę i zwróci wynik bez odchyleń. Dodatkowe zwroty komplikują logikę.
Kontrargumentem jest to, że użycie wczesnych zwrotów pozwala funkcji zakończyć natychmiast po jej zakończeniu, co ogranicza konieczność czytania niepotrzebnej logiki i minimalizuje potrzebę warunkowych zagnieżdżonych bloków, co czyni kod bardziej czytelnym.
Niektórzy programiści wybierają złoty środek i używają wczesnych zwrotów na górze funkcji tylko w celu sprawdzenia parametrów (wyłapania błędnych argumentów), a następnie pojedynczego powrotu później.
Nasze stanowisko jest takie, że wczesne powroty są bardziej pomocne niż szkodliwe, ale zdajemy sobie sprawę, że w praktyce jest odrobina sztuki.
Najlepsza praktyka
Wykorzystuj wczesne powroty, gdy upraszczają logikę funkcji.

