안녕하십니까. BlockDMask입니다.
오늘 공부할 내용은 C++11에 추가된 범위기반 반복문 range based for문 입니다.
혁명이죠. 놀랍죠. 하지만 범위기반 for문이 완전히 for문을 대체하지 못합니다. why? 왜때문이죠?
그럼 살펴보겠습니다.
<목차>
1. C++ range based for문 이란? (기본편 - 값복사)
2. C++ range based for문 예제 1 (순회)
3. C++ range based for문 예제 2 (for와 range based for의 차이)
5. C++ range based for문 이란? (심화편 - reference, const reference)
5. C++ range based for문 reference 예제
6. C++ range based for문 const reference 예제
1. C++ range based for문 이란? (기본편 - 값복사)
▼ C++ 범위기반 for문이란?
기존의 for 반복문과 달리, 시작과 끝점을 알려주지 않아도 알아서 처음부터 끝까지 순회를 해주는 반복문 입니다.
C++11에서부터 사용을 할 수 있습니다.
C# 에서의 foreach와 같다고 생각하면 됩니다. [바로가기]
▼ C++ 범위기반 for문 사용법
for (데이터 타입 elem : 데이터 리스트)
{
당신이 하고싶은 그 모든것들. elem을 이용하면 됩니다.
}
따로 키워드가 있는 것은 아닙니다. for( --- ) 이 괄호 안에를 자세히 살펴보아야 합니다.
데이터 타입 : 데이터 리스트에서 부터 하나씩 받아올 데이터의 타입을 말합니다. 그 데이터는 변수 elem에 들어가게 됩니다.
변수 이름 elem : 데이터를 가지고 있는 변수 이름 입니다.
데이터 리스트 : 배열, vector와 같은 순회가 가능한 데이터 리스트 입니다. 데이터 리스트 앞에 꼭 " : " (콜론)을 붙여줘야 합니다.
▼ for문과 범위기반 for문의 차이점.
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for(int i=0; i<10; ++i)
{
cout << arr[i] << endl;
}
기존의 for문은 이런식으로 했었습니다.
for(int elem : arr)
{
cout << elem << endl;
}
범위기반 for문은 이런식으로 순회하면됩니다.
이렇게 좋아보이는 base ranged for문이 완전히 for 반복문을 대체하지는 못합니다.
왜, why, 왜때문일까요? (그것의 이유는 60초 뒤에)
1. 범위기반 for문에서는 index 정보가 존재하지 않습니다.
index 를 나타내는 아무런 정보가 없기 때문입니다.
기존의 for문에서는 위 예제에서 처럼 index를 나태는 " i " 가 존재하는데 범위기반 for문에는 존재하지 않습니다. 오직 elem이라는 값만 존재할 뿐입니다. index로 구분할 수 있는 여러가지 조절이 힘들다는 단점이 존재합니다. (할 수 있습니다. 코드가 더러워질뿐)
2. 범위기반 for 배열의 요소를 변경할 수 없습니다. (변경 가능한것은 아래 4번 심화편을 봐주세요.)
매 반복문이 돌때마다 int elem : arr 을 통해서 하는 일은 아래와 같습니다.
elem = arr[0];
elem = arr[1];
이런식으로 배열의 요소들이 elem 이라는 변수에 복사됩니다.
그래서 배열의 요소를 내부에서 바꾸려고 elem = 1; 시도를 해도. 복사된 값 이기 때문에 arr[0] 의 값이 바뀌거나 하지않습니다.
그래서 range based for문 내부에서는 배열의 요소를 변경할수 없습니다.
2. C++ range based for문 예제 1 (순회)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | //C++ range based for example. //BlockDMask. #include<iostream> #include<vector> using namespace std; int main(void) { cout << "ex1) 일반적인 배열에서 범위기반 for문 사용법" << endl; cout << "for (int elem : arr)" << endl; int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; for (int elem : arr) { cout << elem << " "; } cout << endl << endl; cout << "ex2) vector같은 std container에서 범위기반 for문 사용법" << endl; cout << "for (int elem : v)" << endl; vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); v.push_back(6); v.push_back(7); v.push_back(8); v.push_back(9); v.push_back(10); for (int elem : v) { cout << elem << " "; } cout << "\niterator를 사용하지 않아도 된다는 것이 좋습니다." << endl; cout << endl << endl; system("pause"); return 0; } | cs |
▲ 범위기반 for문 사용법 1
일반적인 순회예제 입니다. ex2) 에서 원래 for문을 이용했다면
1 | for(vector<int>::iterator iter = v.begin(); iter != v.end(); ++iter) | cs |
이런방식으로 iterator를 이용해서 for문을 사용했어야 했습니다.
하지만 범위기반 for문에서는 이런 번거로운 작업이 없습니다.
3. C++ range based for문 예제 2 (for와 range based for의 차이)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | //C++ range based for example. //BlockDMask. #include<iostream> #include<vector> using namespace std; int main(void) { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); v.push_back(6); v.push_back(7); v.push_back(8); v.push_back(9); v.push_back(10); cout << "ex1) 기존의 반복문을 사용했을때." << endl; cout << "for (vector<int>::iterator iter = v.begin(); iter != v.end(); ++iter)" << endl; for (vector<int>::iterator iter = v.begin(); iter != v.end(); ++iter) { cout << *iter << " "; } cout << endl << endl; cout << "ex2) 범위기반 반복문을 사용했을때." << endl; cout << "for (int elem : v)" << endl; for (int elem : v) { cout << elem << " "; } cout << endl << endl; cout << "ex3) 기존 반복문에서 원래 데이터 변경 확인" << endl; for (vector<int>::iterator iter = v.begin(); iter != v.end(); ++iter) { *iter += 10; cout << *iter << " "; } cout << endl; for (vector<int>::iterator iter = v.begin(); iter != v.end(); ++iter) { cout << *iter << " "; } cout << endl << endl; cout << "ex4) 범위기반 반복문에서 원래 데이터 변경 확인" << endl; for (int elem : v) { elem += 100; cout << elem << " "; } cout << endl; for (int elem : v) { cout << elem << " "; } cout << endl << endl; system("pause"); return 0; } | cs |
▲ 범위기반 for문 사용법 2
1,2번 예제 : 처음부터 끝까지 순회하는 것이라면 범위기반 for문이 훨씬 문장이 짧습니다.
3,4번 예제 : 범위기반 for문의 변수 elem 값을 바꾼다 하더라도, 원래 데이터가 변경되지는 않습니다.
4. C++ range based for문 이란? (심화편 - reference, const reference)
우리는 위에서 기본적인 범위기반 for문을 배웠습니다. 하지만,
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for(int elem : arr)
{
cout << elem << endl;
}
이런식으로 위쪽 기본편에서 배운데로 하게 되면, arr 배열에 있는 인자를 elem 이라는 새로운 변수에 복사를 하게 됩니다.
매 반복문이 돌때마다 아래처럼 복사가 됩니다.
elem = arr[0];
elem = arr[1];
elem = arr[2];
복사를 하게되면 단점이 많습니다.
1. 복사를 했기 때문에 배열의 원래 값를 변경하지 못합니다.
2. 복사를 했기 때문에 복사비용이 발생합니다.
이러한 단점을 보완하기 위해서는 C++의 & (참조자, reference)를 이용하면 됩니다.
(혹시 C++ 참조자 & (reference)에 대한 공부가 필요하다면 [바로가기])
▼ C++ range based for문을 reference로 사용하는 방법.
for(int& elem : arr)
{
elem += 1; //arr[ ] 값도 변경됨.
cout << elem << endl;
}
for(데이터 타입& 변수이름 : 데이터리스트) 와 같이 데이터 타입 뒤에 레퍼런스(&)를 붙이는 방식으로 한다면,
배열의 해당 인자의 값복사가 아닌 변수의 reference(=참조자, 레퍼런스)를 가지고 오게 됩니다.
이렇게 할때의 이점을 아래와 같습니다.
1. 복사비용이 들지 않아서 비용이 감소 합니다.
2. 배열의 원래 원소를 변경할 수 있습니다.
이렇게 되면 다 해결이 되어서 좋지만, 복사비용이 안드는 것은 좋은데 반복문 내부에서 변경이 일어나지 않아야 하는 경우도 존재하죠.
이런 경우에는 const와 reference를 같이 사용하면됩니다.
▼ C++ range based for문을 const와 reference로 사용하는 방법.
for(const int& elem : arr)
{
elem += 1; // 불가능.
cout << elem << endl;
}
for(const 데이터 타입& 변수이름 : 데이터리스트) 이런방식으로 데이터 타입 앞에 const를 붙이면 값 변경이 불가능하게 됩니다.
그러면 복사비용이 들지 않고 배열의 값을 이용할 수 있고, 배열의 값을 변경하지 않는걸 보장할 수 있게 됩니다.
const & 를 사용할지, &를 사용할지 아니면 그냥 복사로 사용할지는 각 상황에 맞게 잘 판단해서 하면 됩니다.
5. C++ range based for문 reference 예제
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | //C++ range based for, reference example. //BlockDMask. #include<iostream> #include<vector> using namespace std; int main(void) { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); v.push_back(6); v.push_back(7); v.push_back(8); v.push_back(9); v.push_back(10); cout << "ex1) 범위기반 반복문 reference를 이용한 데이터 변경" << endl; for (int& elem : v) { elem += 100; cout << elem << " "; } cout << endl; for (int& elem : v) { cout << elem << " "; } cout << endl << endl; system("pause"); return 0; } | cs |
▲ 범위기반 for문 reference 사용법
저 위에 for와 range based for문의 차이 예제에서와 달리, & (래퍼런스, 참조자)를 이용하니까 원본데이터가 바뀐것을 볼 수 있습니다.
6. C++ range based for문 const reference 예제
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | //C++ range based for, const reference example. //BlockDMask. #include<iostream> #include<vector> using namespace std; int main(void) { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); v.push_back(6); v.push_back(7); v.push_back(8); v.push_back(9); v.push_back(10); cout << "ex) 범위기반 반복문 const reference를 이용한 데이터 변경 불가능" << endl; for (const int& elem : v) { //elem += 100; 불가능. cout << elem << " "; } cout << endl; for (int& elem : v) { elem += 100; //가능. cout << elem << " "; } cout << endl; for (const int& elem : v) { cout << elem << " "; } cout << endl << endl; system("pause"); return 0; } | cs |
▲ 범위기반 for문 const reference 사용법
const reference 를 사용한 for문 내부에서는 데이터 값 변경이 불가능 한 것을 볼 수 있습니다.
감사합니다. 새로운 포스팅이 보고싶다면 "구독" 부탁드립니다.
'<개인공부> > [C++]' 카테고리의 다른 글
[C++] map, set의 키를 클래스 구조체로 만드는 방법 (5) | 2019.11.20 |
---|---|
[C++] 파일입출력(ofstream, ifstream)에 대해서. (2) | 2019.11.18 |
[C++] reverse 문자열을 거꾸로 하는 함수에 대해서 (0) | 2019.11.13 |
[C++] string 클래스, 문자열에 대해서 (총정리) (39) | 2019.03.29 |
[C++] trunc 버림 함수에 대해서 (0) | 2019.03.19 |
[C++] round 반올림 함수에 대해서. (1) | 2019.03.19 |
[C++] to_string 함수에 대해서 (int to string) (4) | 2019.03.17 |
[C++] stoi, stof, stol, stod 함수에 대해서 (string to int) (4) | 2019.03.16 |