On this page
article
Algorithm
erase-remove idiom
remove
- 지정한 값과 일치하지 않는 요소를 앞으로 이동시킴
- 컨테이너 크기는 그대로 유지됨
erase
- 컨테이너의 멤버 함수
- 실제 컨테이너의 크기를 줄임
erase-remove idiom
- 제거 대상 요소들을 remove로 뒤로 몰고, erase로 제거
- vector처럼 연속된 메모리를 갖는 컨테이너에 가장 적합
v.erase(std::remove(v.begin(), v.end(), 3), v.end());
ranges::remove (C++20)
- 반환값은 반복자가 아닌, 삭제된 영역을 가리키는 범위 쌍
std::vector v1{1, 3, 1, 3, 1, 3, 10, 3, 9, 3};
auto ret1 = std::remove(v1.begin(), std::next(v1.begin(), 7), 3);
v1.erase(ret1, std::next(v1.begin(), 7));
std::vector v2{1, 3, 1, 3, 1, 3, 10, 3, 9, 3};
auto ret2 = std::ranges::remove(v2.begin(), std::next(v2.begin(), 7), 3);
v2.erase(ret2.begin(), ret2.end());
algorithm vs member function
list에서 erase-remove idiom 비효율적 이유
- remove 호출 시 직접 요소를 제거하는 멤버 함수가 더 효율적
원칙
- 컨테이너에 동일한 이름의 멤버 함수가 있다면 그것을 사용
멤버 함수 존재 이유
- 반복자 요구 조건이 안 맞는 경우 (예: sort는 introsort(quick + heap)을 사용하는데, random access iterator가 없는 list는 다른 방식의 sort 필요)
- 멤버 함수가 내부 구조에 최적화되어 있어 더 효율적임
erase/erase_if (C++20)
erase를 할 때 vector와 list가 다른 불편함 해결
std::vector v{1, 2, 3, 1, 2, 3};
std::list s{1, 2, 3, 1, 2, 3};
// v.erase(std::remove(v.begin(), v.end(), 3), v.end());
// s.erase(std::remove(s.begin(), s.end(), 3), s.end());
// s.remove(3);
auto cnt1 = std::erase(v, 3);
auto cnt2 = std::erase(s, 3);
- erase-remove idiom을 대체함
transform 알고리즘
std::vector v1{1, 2, 3, 4, 5};
std::vector<int> v2;
std::vector<int> v3;
std::ranges::transform(v1, std::back_inserter(v2), square); // v2 : 1, 4, 9, 16, 25
std::ranges::transform(v1, v2, std::back_inserter(v3), add); // v3 : 2, 6, 12, 20, 30
std::ranges::for_each(v3, print);
알고리즘에 전달하는 함수
- 일반 함수
- 함수 객체
- 람다 표현식 (지역 변수 캡처 가능)
- 지역 변수 캡처의 장점때문에 함수 객체 / 람다 표현식 사용 권장
sort(v, std::greater<int>{});
sort(v, std::greater{}); // ~C++ 17
sort(v, {});
Predicate (조건자)
- bool 또는 bool로 변환 가능한 값을 반환하는 함수
- find_if, remove_if 등에서 조건자로 사용
find_if(v, [] (int n) { return n % 3 == 0; });
- sort와 달리 find가 아닌 find_if인 이유: C++98에서는 같은 함수 이름으로 여러 템플릿 만들 수 없었음
Projection (C++20)
상황
Point 객체를 갖는 컨테이너에서 y가 3인 요소를 찾는 경우
방법
- find_if
- projection
Projection
알고리즘에서 요소 자체가 아닌 요소의 특정 멤버나 속성만을 기준으로 동작하도록 만드는 기능 대부분의 c++20 ranges에서지원
std::ranges::algorithm(container, comparator, projection);
기존과 비교
1. std::sort(v.begin(), v.end(), [](const Point& a, const Point& b) {
return a.y < b.y;
});
2. std::ranges::sort(v, std::less{}, &Point::y);
find 예시시
auto ret1 = std::ranges::find(v, 3, &Point::y);
auto ret2 = std::ranges::find(v, 3, &Point::get_y);