for_each()
for_each란?
algorithm
헤더에 정의된 STL함수로 주어진 범위 내의 모든 요소를 순회하면 요소 값을 함수에 전달하는 기능을 수행한다.
std::for_each(시작 iterator, 끝 iterator, 함수 또는 람다 표현식)
vector의 요소를 출력하는 예제
#include <iostream>
#include <vector>
#include <algorithm>
void print(int value)
{
std::cout << value << ", ";
}
int main()
{
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::for_each(numbers.begin(), numbers.end(), print);
return 0;
}
실행 결과는 다음과 같다.
1, 2, 3, 4, 5
[[vector]]로 선언된 numbers
의 시작(begin()
)과 끝(end()
)의 [[iterator]]를 for_each
함수의 매개변수에 전달 인자로 전달하고, numbers의 요소를 전달하면서 실행할 함수를 마지막 매개변수 위치에 넣어준다.
for_each()의 전달 인자가 되는 함수에 매개변수가 존재하지 않는 경우?
[[#vector의 요소를 출력하는 예제]]에서 void print(int value)
함수에 매개변수 int valeu
가 없다면 컴파일러는 다음과 같은 에러를 발생 시킨다.
void print()
{
std::cout << "print()";
}
int main()
{
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::for_each(numbers.begin(), numbers.end(), print);
return 0;
}
위와 같이 코드를 작성할 경우 void print()
함수는 매개변수가 없기 때문에 전달받은 vector
요소를 처리할 수 없어 에러가 발생하게 된다.
for_each에서 호출하는 함수의 반환형
for_each
에 매개변수로 전달해 실행하는 함수의 반환형은 무시된다. 아래 코드는 컴파일 에러도 발생하지 않고 [[#vector의 요소를 출력하는 예제]]에서 제시한 코드의 실행결과와 동일한 실행결과를 보인다.
#include <iostream>
#include <vector>
#include <algorithm>
int print(int value)
{
std::cout << value << ", ";
return 1;
}
int main()
{
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::for_each(numbers.begin(), numbers.end(), print);
return 0;
}
for_each()의 전달 인자가 되는 함수의 매개 변수가 두 개 이상인 경우?
[[#for_each()의 전달 인자가 되는 함수에 매개변수가 존재하지 않는 경우?]]와 마찬가지로 컴파일 에러가 발생한다. for_each()
에 전달 인자로 전달되는 함수의 전달 인자는 반드시 1개여야 한다.
for_each()에 [[lambda(람다)]]적용
vector의 요소를 출력하는 예제(lambda)
[[#vector의 요소를 출력하는 예제]]에서 void print(int value)
를 람다식으로 대체해보자.
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std:;vector<int> numbers = {1, 2, 3, 4, 5};
std::for_each(numbers.begin(), numbers.end(), [](int value)) {
std::cout<< value << ", ";
};
return 0;
}
람다를 사용하면 코드를 더 짧고 명확하게 작성 할 수 있다.
for_each()를 왜 사용해야 하는가?
for_each()
와 for
반복문 비교
for_each()
와 전통적인 for
반복문의 성능 차이는 거의 없다고 봐도 무방하다. for_each()
가 더 효율적이고 간결하다고 말하는 이유는 코드의 가독성
과 표현력
에 대한 차이점 때문이다.for_each()
를 사용하는 이유 중 하나는 코드의 간결성
과 함수형 프로그래밍
스타일을 강조 할 수 있다는 점이 있다.
std::for_each(numbers.begin(), numbers.end(), print)
이 코드는 컨테이너의 모든 요소를 pinrt
함수의 매개 변수에 전달 인자로 전달한다는 것을 명확하게 보여준다. 또한 컨테이너와 알고리즘(여기서는 print
함수)을 분리해서 코드의 의도를 더 명확하게 표현할 수 있다.
반면에 for
문을 사용하면
for(int i = 0; i < 5; i++){
std:;cout << numbers[i] << ", ";
}
이 방식도 for_each()
를 사용한 경우와 같은 결과를 보이지만 iterator
의 범위를 직접 제어하고 인덱스를 사용해야 하므로 코드가 조금 더 절차적이고 덜 추상화된 형태가 된다. 따라서 코드 길이가 길어지거나 복잡해질 경우 개발자의 실수를 유발할 가능성이 있다.
알고리즘과 데이터를 분리
for
를 사용하게 되면 알고리즘과 데이터가 엉켜서 명령형 코딩 스타일을 따르게 된다. for_each()
를 사용하게 되면 함수형 스타일로 처리를 할 수 있게 한다.
아래 코드와 같이 for
문을 사용하면 각 요소에 대해 무엇을 할 것인가?(알고리즘) 와 컨테이너에서 데이터를 어떻게 가져올 것인가?(데이터 처리) 를 혼합해서 작성해야 한다.
for(int i = 0; i < numbers.size(); ++i) { // 데이터를 어떻게 가져올 것인가 ?
numbers[i] *= 2; // 알고리즘
}
하지만 for_each()
를 사용하면 데이터 처리는 컨테이너에 위임하고, 알고리즘 x2만을 집중해서 처리할 수 있다.
std::for_each(numbers.begin(), numbers.end(), [](double& num)) {
num *= 2;
}
이렇게 람다식을 적용하면 데이터와 알고리즘의 책임이 분리되어 코드의 유지보수성이 높아진다.
동일한 코드 패턴의 재사용성
반복 작업에 대해 동일한 패턴을 재사용 할 수 있다. 예를 들어 여러 vector
나 list
를 처리할 때, 코드를 반복해서 작성하지 않고 동일한 패턴으로 쉽게 적용 할 수 있다.
void print(double i)
{
std::cout << i << ", ";
}
std::vector<double> nums1 = {1.0, 2.0, 3.0};
std::vector<double> nums2 = {11.0, 12.0, 13.0};
std::for_each(nums1.begin(), nums1.end(), print);
std::for_each(nums2.begin(), nums2.end(), print);
이와 같이 작성하면 코드 중복을 줄이고 같은 패턴의 작업을 효율적으로 처리할 수 있다. 필요에 따라 람다식이나 함수 객체로 바꿔 줄 수 있다.
모든 iterator 사용 가능
계속해서 예를 들고 있는 vector
뿐만 아니라 [[list]], [[set]], [[map]] 등 다양한 컨테이너에서 사용 가능하다.
직관적인 의미 전달
코드의 의미를 직관적으로 전달할 수 있는 장점이 있다. for
문은 순회를 직접 제어하는 명령형 프로그래밍 스타일로 코드가 복잡해질 수 있지만, for_each
는 각 요소에 대해 어떤 작업을 할지 라는 개념을 쉽게 표현할 수 있다.
std::for_each(numbers.begin(), numbers.end(), print);
이 코드는 vector
의 각 요소를 print
함수로 출력한다. 라는 적을 직관적으로 이해 할 수 있다.
-끝-
'Programming language > C++' 카테고리의 다른 글
[C++] 디폴트 매개변수, 매개변수의 default 값 (1) | 2024.10.13 |
---|---|
[C++] 오버로딩(Overloading) (0) | 2024.09.01 |
[C++] 함수 오버라이딩(override) (0) | 2024.08.31 |
[C++] 디폴트 복사 생성자(Default copy constructor) (0) | 2024.05.31 |
[C++] 소멸자(Destructor), 디폴트 소멸자(Default destructor) (0) | 2024.05.03 |