[C++][algorithm] 실수하기 딱 좋은 remove 함수
vector에서 홀수인 값을 지워야 한다면?
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<int> v;
v.push_back(1);
v.push_back(4);
v.push_back(3);
v.push_back(5);
v.push_back(8);
v.push_back(2);
// 1 4 3 5 8 2
}
위와 같은 벡터가 있을 때, 홀수의 값을 찾아지우는 방법은 여러가지가 있지만 쉽게 생각할 수 있는 방법은 벡터의 erase 함수를 이용해서 반복문을 돌면서 지우는 방법이 있다.
이것 외에도 alorithm
라이브러리에 정의되어 있는 remove 함수를 사용할 수도 있다. 함수의 사용법을 쓱 보고 보통 아래와 같은 방법을 사용해볼 수 있을 것이다.
// 함수 객체 활용
struct IsOdd
{
bool operator() (int n)
{
return (n % 2) != 0;
}
};
// remove_if는 iterator를 반환함
vector<int>::iterator it = remove_if(v.begin(), v.end(), IsOdd());
1 4 3 5 8 2
의 원소를 가지고 있는 벡터에서 홀수의 값을 제거하고 나면 4 8 2
가 벡터에 남아있을 것으로 마땅히 기대할 것이다. 그런데 디버깅 모드로 벡터의 값을 확인해보면 4 8 2 5 8 2
라는 묘한 값을 가지고 있다. 무슨 일이 일어난걸까?
remove_if의 구현부
cppreference.com에서 remove_if를 확인해보면 아래와 같다.
template<class ForwardIt, class UnaryPredicate>
ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPredicate p)
{
first = std::find_if(first, last, p);
if (first != last)
for(ForwardIt i = first; ++i != last; )
if (!p(*i))
*first++ = std::move(*i);
return first;
}
단순히 벡터의 원소를 지우는 것이 아니라 move를 이용해서 짝수인 값을 앞으로 땡겨온다는 것을 확인할 수 있다. 결과적으로 짝수를 앞으로 다 떙겨오고난 이후의 위치를 가리키는 iterator를 반환한다.
그러니까 벡터의 원소를 삭제해주는 작업을 추가해주지 않으면 원하는 결과를 얻지 못하고, 프로젝트에 잘못된 영향을 끼칠 가능성이 생긴다.
그래서 우리가 기대하는 4 8 2
의 값을 얻기 위해서는 아래의 코드를 추가해줘야한다.
v.erase(it, v.end()); // 짝수값 이후를 나타내는 위치부터 vector의 끝까지 지워버리기