C++ for_each문 개념과 사용법 설명
C++에는 기본 문법인 for문이 있습니다.
for문으로 모든 반복문을 만들 수 있고 실행시킬 수 있습니다.
하지만 단순 for문으로 만들기엔 귀찮거나 손이 많이가는 반복문을 만들 수 밖에 없는 상황이 종종 존재합니다.
한가지 예시를 들겠습니다.
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
void print_fnc(int n) {
cout << n << " ";
}
int main(void) {
int arr[10]{ 1, 2, 3, 4, 5, 6, 7, 8, 9 ,10 };
vector<int> v = { 5,2,3,4,5 };
vector<int>::iterator itr = v.begin();
cout << "배열 호출 : ";
for (int i = 0; i < 10; i++)
cout << arr[i] << " " ;
cout << endl;
cout << "백터 호출 : ";
for (int i = 0; i < 5; i++)
cout << v.at(i) << " ";
cout << endl;
cout << "iterator 호출 : ";
for (itr; itr != v.end(); itr++)
cout << *itr << " ";
cout << endl;
cout << "함수 호출 : ";
for (int i = 0; i < 10; i++)
print_fnc(arr[i]);
return 0;
}
실행결과
간단한 배열과 백터를 선언하고 모든 요소들을 for문을 이용해 출력하는 예제입니다.
불편함 없이 사용이 가능하지만 C++의 라이브러리중엔 for_each문이 존재 합니다.
for_each문의 사용 이유는 다음과 같습니다.
1. 코드의 간결화
2. 함수 객체를 이용한 inline화
3. 사용자가 for_each문의 기능을 정의해 유연성을 부여.
사용법은 아래와 같습니다.
헤더파일 <algorithm>에 의해 정의 됨.
1. 반환 값 :
for_each는 값을 반환할 수 있습니다. 반환되는 것은 사용자로부터 전달 받은 함수 또는 함수 객체의 형식으로 반환 됩니다.
2. 시작 주소와 끝 주소 값 :
for_each는 인자를 주소 값으로 전달 받습니다. 따라서 첫 번째 매개 변수로 값의 시작점인 주소 값을 받고,
두 번째 인자로 값의 마지막 요소 값을 가르키는 주소 값을 전달 받습니다.
(주의해야 할 점은 2번째 인자를 전달 받을 때 전달 받은 주소 값 까지 출력하는 것이 아니라
전달 받은 주소 값 전 까지의 값만을 출력해 보여 줍니다.)
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
void print_fnc(int n) {
cout << n << " ";
}
int main(void) {
int arr[10]{ 1, 2, 3, 4, 5, 6, 7, 8, 9 ,10 };
cout << "arr [9]의 값 : " << arr[9] << endl;
for_each(arr, &arr[9], print_fnc);
cout << endl;
cout << "arr [10]의 값 : " << arr[10] << endl;
for_each(arr, &arr[10], print_fnc);
return 0;
}
실행 결과
이 결과를 보면 이해하시리라 믿습니다.!!!
3. 사용자가 정의한 함수 or 함수 객체
사용자가 정의한 함수 객체를 통해 간략하게 출력을 할 수 있습니다.
뿐만 아니라 Lambda를 이용해 함수나 객체를 정의할 필요없이 바로 실행되게 만들 수도 있습니다.
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
void print_fnc(int n) {
cout << n << " ";
}
int main(void) {
vector<int> v = { 1,2,3,4,5 };
vector<int>::iterator itr = v.begin();
cout << "for_each문 함수 호출 : ";
for_each(v.begin(), v.end(), print_fnc); //함수 호출
cout << endl;
cout << "for_each문 Lambda 호출 : ";
for_each(itr, itr + v.size(), [](auto& n) { //Lambda 호출
cout << n << " ";
});
return 0;
}
실행결과
람다를 활용해 함수를 만들지 않고 바로 출력되는걸 알 수 있습니다.
여기서 함수 인자 값에 대한 부분이 궁금해 지는데,
for_each문 내부로 들어가게 되면 첫 번째 인자 값으로 받은 주소 값을 바탕으로 사용자가 정의한 함수의 매개변수로 전달하게 됩니다.
(말로 풀어쓰니깐 뭔말인지 모르겠으니 그림으로 설명할께요...)
(함수 호출경우도 동일하게 동작합니다.)
그리고 for_each문은 내부적으로 함수 전달 부분이 inline이 선언되어 있습니다.
물론 무조건 inline화 되는건 아니지만 기본적으로 inline을 지향하고 있다는 말이죠.
for_each문의 장점이자 단점은 한번 실행하면 끝까지 실행한다는 점입니다.
즉, 중간에 중단이 불가능 합니다.
때문에 if문을 활용한 break는 불가능 하단 말이죠.
따라서 사용할 때 프로그래머의 필요에 맞게 사용하는것이 좋을 것 같습니다.