프로그래밍/C++

C++ for_each문 개념과 사용법 설명

Hwan2 2019. 8. 1. 19:19
반응형

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는 불가능 하단 말이죠.

 

따라서 사용할 때 프로그래머의 필요에 맞게 사용하는것이 좋을 것 같습니다.

 

 

 

반응형