break와 continue
break로 가장 안쪽 대상 반복을 종료하고 continue로 현재 반복만 건너뛰는 정확한 도착 지점과 안전 점검 기준을 구분합니다.
반복 도중에 찾던 값을 이미 찾았다면 나머지 반복은 필요 없고, 처리할 수 없는 항목을 만났다면 그 항목만 건너뛰고 다음으로 넘어가면 됩니다. 이럴 때 쓰는 것이 반복을 끝내는 break와 이번 회차의 나머지를 건너뛰는 continue입니다.
두 문장은 남은 문장을 조건 없이 건너뛰는 점프이므로, 어느 문장을 대상으로 하는지, 실행이 어디로 가는지, 그 사이에 어떤 작업이 빠지는지를 함께 읽어야 합니다. 아래 그림은 두 문장의 대상과 반복문 종류별 도착 지점을 정리한 것입니다.
C++ · JUMP TARGET CONTRACT
break와 continue는 가장 안쪽 대상과 도착점이 다르다
키워드보다 둘러싼 문장과 도착 지점을 먼저 읽습니다. break는 대상 문장을 끝내고, continue는 현재 반복의 남은 본문을 건너뜁니다. 가장 안쪽의 적격 문장이 실제 제어 이동을 결정합니다.
| 실행 경로 | 대상이 되는 문장 | 건너뛰는 범위 | 다음 실행 |
|---|---|---|---|
break |
가장 안쪽 반복문 또는 switch |
대상 문장의 나머지; 반복이면 남은 횟수 | 끝난 문장 바로 다음 |
continue · while |
가장 안쪽 while |
현재 본문의 남은 문장 | 조건 검사 |
continue · do |
가장 안쪽 do 반복 |
현재 본문의 남은 문장 | 본문 뒤 조건 검사 |
continue · for |
가장 안쪽 고전 for |
현재 본문의 남은 문장 | 반복식, 그다음 조건 |
continue · 범위 for |
가장 안쪽 범위 반복 | 현재 원소의 남은 처리 | 반복자 증가, 그다음 조건 |
break · 대상 종료
가장 안쪽 반복문 또는 switch → 그 문장 다음
현재 본문의 나머지뿐 아니라 대상 반복의 남은 횟수도 실행하지 않습니다.
continue · 현재 반복 생략
가장 안쪽 반복문의 반복 계속 지점
switch는 continue의 대상이 아닙니다.
while · do
while은 다음 조건으로, do 반복은 본문 뒤 조건으로 이어집니다.
고전·범위 for
고전 형식은 반복식을, 범위 형식은 반복자 증가를 거친 뒤 조건을 다시 검사합니다.
반복문 안의 switch
while (ready()) {
switch (kind()) {
// switch만 종료
case stop: break;
// while 조건으로
case skip: continue;
}
work();
}
break는 더 가까운 switch를 선택하지만, continue는 바깥 반복문을 선택합니다.
중첩 반복문
두 키워드 모두 가장 안쪽의 적격 대상 하나를 선택
C++에는 여러 반복을 이름으로 지정해 한 번에 끝내는 labeled break 문법이 없습니다. 여러 단계 종료는 함수 분리·상태 전달 같은 구조로 의도를 드러냅니다.
switch를 다룹니다. 최신 초안의 expansion statement 같은 별도 문법까지 일반화하지 않습니다.break: 반복 끝내기
break는 자신을 둘러싼 반복문이나 switch 가운데 가장 안쪽의 하나를 끝내고, 그 문장 바로 다음으로 실행을 옮깁니다. 대상이 반복문이면 본문의 나머지뿐 아니라 남은 회차도 모두 실행하지 않습니다.
#include <iostream>
int main() {
for (int i = 1; i <= 10; ++i) {
if (i == 5) {
std::cout << "\nstop at " << i << '\n';
break;
}
std::cout << i << ' ';
}
std::cout << "after loop\n";
}1 2 3 4
stop at 5
after loopi가 5일 때 break가 실행되면 그 회차의 출력문도, 6부터 10까지의 회차도 실행되지 않습니다. 이때는 반복식 ++i도 실행되지 않고, 곧바로 루프 다음의 after loop 출력으로 갑니다.
break가 가장 잘 어울리는 곳은 탐색입니다. 다음 프로그램은 배열에서 처음 나오는 음수의 위치를 찾습니다.
#include <iostream>
int main() {
int values[]{4, 7, -2, 9, -5};
int found{-1};
for (int i = 0; i < 5; ++i) {
if (values[i] < 0) {
found = i;
break;
}
}
std::cout << "first negative at " << found << '\n';
}first negative at 2인덱스 2의 -2를 찾으면 그 뒤의 9와 -5는 검사하지 않습니다. found를 -1로 시작한 것은 음수가 없을 때를 나타내기 위해서이며, 음수가 하나도 없으면 반복이 끝까지 돈 뒤 -1이 출력됩니다.
중첩 루프와 break
break는 가장 안쪽의 대상 하나만 끝냅니다. 중첩 루프의 안쪽에서 break를 실행하면 안쪽 루프만 끝나고, 바깥 루프는 다음 회차로 계속 진행합니다.
#include <iostream>
int main() {
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
if (i == 1 && j == 1) {
break;
}
std::cout << i << j << ' ';
}
std::cout << '\n';
}
}00 01 02
10
20 21 22i가 1이고 j가 1일 때 안쪽 루프가 끝나므로 둘째 줄에는 10만 출력되지만, 바깥 루프는 줄바꿈을 출력하고 i가 2인 회차로 넘어갑니다. C++23까지의 표준에는 바깥 루프에 이름을 붙여 여러 단계를 한 번에 끝내는 문법이 없습니다.
여러 단계를 함께 끝내야 하면 바깥 루프도 검사하는 표시 변수(flag)를 두거나, 탐색 부분을 함수로 나누어 return으로 함수 전체를 끝냅니다. 함수는 6장에서 다루고, 여기서는 표시 변수를 씁니다.
#include <iostream>
int main() {
bool found{false};
for (int i = 1; i <= 9 && !found; ++i) {
for (int j = 1; j <= 9; ++j) {
if (i * j == 24) {
std::cout << i << " x " << j << '\n';
found = true;
break;
}
}
}
}3 x 8곱이 24인 첫 쌍은 i가 3일 때의 j 8입니다. 안쪽의 break가 안쪽 루프를 끝내면, 바깥 루프는 반복식으로 i를 4로 만든 뒤 조건 !found가 거짓이어서 끝납니다. 이처럼 바깥 조건에 표시 변수를 넣어 두면 어느 단계까지 끝나는지 코드에 드러납니다.
continue: 이번 회차 건너뛰기
continue는 현재 본문의 나머지를 건너뛰고, 자신을 둘러싼 가장 안쪽 반복문의 다음 회차로 넘어갑니다. switch는 continue의 대상이 아니며, 도착 지점은 반복문의 종류에 따라 다릅니다.
| 반복문 | continue 다음에 실행되는 것 |
|---|---|
while | 조건 검사 |
do-while | 본문 뒤의 조건 검사 |
for | 반복식, 그다음 조건 검사 |
범위 기반 for | 다음 원소로 넘어가기, 그다음 끝인지 검사 |
#include <iostream>
int main() {
for (int i = 1; i <= 10; ++i) {
if (i % 2 != 0) {
continue;
}
std::cout << i << ' ';
}
std::cout << '\n';
int divisors[]{10, 5, 0, 8};
for (int d : divisors) {
if (d == 0) {
std::cout << "skip zero\n";
continue;
}
std::cout << "100 / " << d << " = " << 100 / d << '\n';
}
}2 4 6 8 10
100 / 10 = 10
100 / 5 = 20
skip zero
100 / 8 = 12첫 루프는 i가 홀수일 때 출력문을 건너뛰지만, for의 반복식 ++i는 그대로 실행되므로 다음 회차로 정상 진행합니다. 둘째 루프는 0을 만나면 나눗셈을 건너뛰고 다음 원소인 8로 넘어가며, 100 / 8은 정수 나눗셈이어서 12입니다. 0으로 나누면 정의되지 않은 동작이므로, 이렇게 처리할 수 없는 항목을 먼저 걸러 내는 데 continue를 씁니다.
continue가 갱신을 건너뛰지 않게
for에서는 continue 뒤에도 반복식이 실행되지만, while과 do-while에는 반복식 자리가 없습니다. 그래서 본문 끝에 둔 갱신을 continue가 건너뛰면, 같은 값으로 조건 검사를 되풀이해 반복이 끝나지 않습니다.
break와 continue가 건너뛰는 작업 감사
유효하지 않은 항목에서 while의 continue는 index를 유지하고 for의 continue는 반복식으로 증가시키는 독립 실행 차이가 코드로 제시된다.
C++ · SKIPPED WORK AUDIT
점프가 갱신·결과·정리를 건너뛰는지 확인한다
점프 사이에 생략되는 작업이 반복의 안전성을 결정합니다. 도착 지점만 맞아도 충분하지 않습니다. 진행 상태, 결과 반영, 관측, 자원 수명이 모든 경로에서 유지되는지 확인합니다.
while의 continue는 ++index를 건너뛰어 같은 조건으로 돌아간다. for의 continue는 반복식 ++index를 수행하고 다음 조건으로 돌아간다. 두 프로그램은 독립 비교다.
관계도 해설과 예제 원자료
위험 · 갱신을 건너뛰는 continue
std::size_t index = 0;
while (index < items.size()) {
if (!valid(items[index])) {
continue;
}
use(items[index]);
++index;
}
유효하지 않은 항목에서는 index가 변하지 않아 같은 조건과 원소를 다시 만납니다.
안전 · 반복 계속 지점이 갱신을 보장
for (std::size_t index = 0;
index < items.size();
++index) {
if (!valid(items[index])) {
continue;
}
use(items[index]);
}
continue 뒤에도 고전 for의 반복식이 실행되므로 다음 인덱스로 진행합니다.
-
대상 문장을 표시한다
중첩 반복과
switch가운데 실제로 가장 안쪽에 있는 적격 대상을 찾습니다. -
반복 계속 지점을 표시한다
while·do의 조건, 고전for의 반복식, 범위for의 반복자 증가를 구분합니다. -
생략되는 부수 효과를 나열한다
상태 갱신, 결과 저장, 로그, 커밋, 수동
release()가 점프 아래에 있지 않은지 확인합니다. -
자원 수명은 RAII로 분리한다
점프로 범위를 벗어나면 생성된 자동 객체는 역순으로 파괴됩니다. 그러나 아래쪽의 수동 정리 호출은 건너뛸 수 있으므로 객체 수명으로 정리를 표현합니다.
-
여러 단계 종료는 구조로 드러낸다
바깥 반복까지 끝내야 한다면 상태를 전달하거나 탐색을 함수로 분리해
return합니다. 한 개의break가 여러 반복을 끝내지는 않습니다.
break와 continue는 자원 관리 기법이 아닙니다. 모든 제어 경로에서 유지돼야 하는 불변식과 수명을 먼저 설계하고, 점프는 가까운 조건에서 의도를 드러내는 데 사용합니다.이 예의 조건
- 본문과 원 도표에 제시된 사례의 입력·조건을 사용합니다. 설명용 수치나 독립 비교 경로는 각 단계에 표시합니다.
- 현재 상태·값과 전환 근거의 위치는 모든 단계에서 같습니다. 조건이 맞지 않거나 실행되지 않은 경로를 성공한 동작으로 해석하지 않습니다.
| 관찰·상황 | 값·보충 정보 | 변화·이유 |
|---|---|---|
| 유효하지 않은 항목 while과 for의 현재 index를 비교한다. |
|
|
| continue 대상 본문 이후로 건너뛰는 목적지가 다르다. |
|
|
| 다음 index 다음 검사에 사용할 위치가 달라진다. |
|
|
break와 continue가 건너뛰는 작업 감사
유효하지 않은 항목에서 while의 continue는 index를 유지하고 for의 continue는 반복식으로 증가시키는 독립 실행 차이가 코드로 제시된다.
C++ · SKIPPED WORK AUDIT
점프가 갱신·결과·정리를 건너뛰는지 확인한다
점프 사이에 생략되는 작업이 반복의 안전성을 결정합니다. 도착 지점만 맞아도 충분하지 않습니다. 진행 상태, 결과 반영, 관측, 자원 수명이 모든 경로에서 유지되는지 확인합니다.
while의 continue는 ++index를 건너뛰어 같은 조건으로 돌아간다. for의 continue는 반복식 ++index를 수행하고 다음 조건으로 돌아간다. 두 프로그램은 독립 비교다.
관계도 해설과 예제 원자료
위험 · 갱신을 건너뛰는 continue
std::size_t index = 0;
while (index < items.size()) {
if (!valid(items[index])) {
continue;
}
use(items[index]);
++index;
}
유효하지 않은 항목에서는 index가 변하지 않아 같은 조건과 원소를 다시 만납니다.
안전 · 반복 계속 지점이 갱신을 보장
for (std::size_t index = 0;
index < items.size();
++index) {
if (!valid(items[index])) {
continue;
}
use(items[index]);
}
continue 뒤에도 고전 for의 반복식이 실행되므로 다음 인덱스로 진행합니다.
-
대상 문장을 표시한다
중첩 반복과
switch가운데 실제로 가장 안쪽에 있는 적격 대상을 찾습니다. -
반복 계속 지점을 표시한다
while·do의 조건, 고전for의 반복식, 범위for의 반복자 증가를 구분합니다. -
생략되는 부수 효과를 나열한다
상태 갱신, 결과 저장, 로그, 커밋, 수동
release()가 점프 아래에 있지 않은지 확인합니다. -
자원 수명은 RAII로 분리한다
점프로 범위를 벗어나면 생성된 자동 객체는 역순으로 파괴됩니다. 그러나 아래쪽의 수동 정리 호출은 건너뛸 수 있으므로 객체 수명으로 정리를 표현합니다.
-
여러 단계 종료는 구조로 드러낸다
바깥 반복까지 끝내야 한다면 상태를 전달하거나 탐색을 함수로 분리해
return합니다. 한 개의break가 여러 반복을 끝내지는 않습니다.
break와 continue는 자원 관리 기법이 아닙니다. 모든 제어 경로에서 유지돼야 하는 불변식과 수명을 먼저 설계하고, 점프는 가까운 조건에서 의도를 드러내는 데 사용합니다.이 예의 조건
- 본문과 원 도표에 제시된 사례의 입력·조건을 사용합니다. 설명용 수치나 독립 비교 경로는 각 단계에 표시합니다.
- 현재 상태·값과 전환 근거의 위치는 모든 단계에서 같습니다. 조건이 맞지 않거나 실행되지 않은 경로를 성공한 동작으로 해석하지 않습니다.
| 관찰·상황 | 값·보충 정보 | 변화·이유 |
|---|---|---|
| 유효하지 않은 항목 while과 for의 현재 index를 비교한다. |
|
|
| continue 대상 본문 이후로 건너뛰는 목적지가 다르다. |
|
|
| 다음 index 다음 검사에 사용할 위치가 달라진다. |
|
|
그림의 while 코드는 유효하지 않은 항목을 만나면 continue로 ++index를 건너뛰어, 같은 index로 조건과 같은 항목을 다시 만납니다. 같은 일을 for로 쓰면 continue 뒤에도 반복식 ++index가 실행되어 다음 항목으로 넘어갑니다. while을 써야 한다면 갱신을 continue보다 앞에 두어, 모든 경로가 갱신을 지나게 합니다.
#include <iostream>
int main() {
int count{0};
while (count < 5) {
++count;
if (count == 3) {
continue;
}
std::cout << count << ' ';
}
std::cout << '\n';
}1 2 4 5++count가 본문 맨 앞에 있으므로 count가 3인 회차에서 continue해도 이미 갱신이 끝난 상태입니다. 그래서 3만 빠지고 5에서 조건이 거짓이 되어 끝납니다. 갱신이 본문 맨 앞으로 옮겨 가면서 출력되는 값이 0부터 4가 아니라 1부터 5가 되었다는 점도 함께 확인합니다.
switch 안의 break와 continue
반복문 안에 switch가 있으면 두 문장의 대상이 달라집니다. break는 더 가까운 switch를 끝내지만, continue는 switch를 대상으로 하지 않으므로 바깥 반복문으로 갑니다.
#include <iostream>
int main() {
for (int i{0}; i < 3; ++i) {
switch (i) {
case 0: std::cout << "A"; break;
case 1: std::cout << "B"; continue;
default: std::cout << "C"; break;
}
std::cout << "X";
}
std::cout << '\n';
}AXBCXi가 0이면 break가 switch만 끝내므로 switch 다음의 X까지 출력합니다. i가 1이면 continue가 바깥 for의 다음 회차로 가므로 X를 건너뛰고 반복식 ++i로 갑니다. i가 2이면 C와 X를 출력하므로, 회차별 출력 AX, B, CX가 이어져 AXBCX가 됩니다.
건너뛰는 작업 점검하기
break와 continue는 그 아래에 적힌 갱신, 결과 반영, 로그 출력을 모두 건너뜁니다. 블록을 벗어날 때 그 블록의 지역 변수는 자동으로 정리되지만, 코드 아래쪽에 직접 적어 둔 정리 호출은 실행되지 않습니다. 그래서 반드시 실행되어야 하는 정리는 점프 아래에 두지 않고, 뒤의 장에서 볼 RAII처럼 객체가 사라질 때 정리되는 방식으로 맡깁니다.
점프가 많아져 정상 흐름을 따라가기 어렵다면 조건을 다시 묶거나, 탐색과 처리를 함수로 나누는 편이 읽기 쉽습니다. 점프마다 대상 문장, 도착 지점, 건너뛰는 작업을 확인하는 습관을 들이면 대부분의 실수를 미리 막을 수 있습니다.
정리
break는 가장 안쪽의 반복문이나switch를 끝내고 그 다음 문장으로 가며, 반복식도 실행하지 않습니다.- 중첩 루프의
break는 안쪽 루프 하나만 끝내므로, 여러 단계를 끝내려면 표시 변수나 함수의return을 씁니다. continue는 현재 회차의 나머지를 건너뛰고,while은 조건으로,for는 반복식을 거쳐 조건으로 갑니다.while에서continue가 갱신을 건너뛰면 반복이 끝나지 않으므로, 갱신을continue보다 앞에 둡니다.- 반복문 안의
switch에서break는switch만 끝내고,continue는 바깥 반복문의 다음 회차로 갑니다.
연습 문제
1. continue를 break로
switch_in_loop.cpp의 case 1에서 continue만 break로 바꾸면 출력은 무엇인가요?
해설 보기
세 break가 모두 switch만 끝내므로 회차마다 X를 출력해 AXBXCX가 됩니다. continue가 있던 회차에서만 X가 빠졌던 것이므로, 두 문장의 대상이 다르다는 점이 출력에 그대로 드러납니다.
2. 안쪽 루프의 조건 바꾸기
nested_break.cpp의 조건을 if (j == 1)로 바꾸면 출력은 어떻게 되나요?
해설 보기
모든 i에서 j가 1이 되는 순간 안쪽 루프가 끝나므로, 줄마다 j가 0인 쌍 하나만 출력됩니다. 출력은 00, 10, 20의 세 줄이며, 바깥 루프는 세 번 모두 실행됩니다.
3. 찾지 못한 경우
find_pair.cpp에서 24를 100으로 바꾸면 무엇이 출력되나요? 바깥 루프는 몇 번 실행되나요?
해설 보기
1부터 9까지의 두 수를 곱해 100이 되는 쌍은 없으므로 아무것도 출력되지 않습니다. found가 끝까지 거짓이어서 바깥 루프는 i가 1부터 9까지 9번 모두 실행되고, 안쪽 본문은 81번 실행됩니다.
다음 글 goto 문에서는 레이블로 실행을 옮기는 goto의 규칙과, 지금까지 본 구조적 제어문으로 대신하는 방법을 다룹니다.