#stl 반복자 어댑터(Iterator Adaptors) - inserter(), back_inserter(), front_inserter()

1 minute read

transform(), copy() 알고리즘과 같이 연산을 하거나 단순 복사를 하는 알고리즘을 사용할 때, 결과물을 쓰기 위한 반복자(iterator)를 함수 인자로 받는다. operator = 로 값을 쓰기 때문에 결과물을 특정 컨테이너 뒤에 삽입하려면 귀찮은 과정을 거쳐야 한다. 이럴 때 쓰라고 만들어 놓은 게 반복자 어댑터이다. 내부 구현을 보면 operator = 를 오버로딩해서 push_back(), push_front(), insert() 를 호출한다.

// 벡터 정의
int arr1[] = { 0, 1, 2, 3, 4 };
int arr2[] = { 5, 6, 7, 8, 9 };

typedef std::vector<int>    IntegerVector;
IntegerVector v1(arr1, arr1 + sizeof(arr1) / sizeof(arr1[0]));
IntegerVector v2(arr2, arr2 + sizeof(arr2) / sizeof(arr2[0]));

// v1 벡터의 원소를 v2 벡터에 append한다.
v2.resize(v1.size() + v2.size());
std::copy(v1.begin(), v1.end(), v2.end() - v1.size());

// 콘솔 출력
std::copy(
    v2.begin(),
    v2.end(),
    std::ostream_iterator<int>(std::cout, " "));

반복자 어댑터를 사용 안 하면 resize() 와 반복자 연산을 해야 한다.

v2.reserve(v1.size() + v2.size());
std::copy(v1.begin(), v1.end(), std::back_inserter(v2));

reserve() 는 원소가 많을 때 여러 번의 메모리 할당을 막으려고 호출한다. 확실히 반복자 어댑터가 간편하고 코드도 더 직관적이다. 이거 땜씨롱 반복자 어댑터를 쓰는 거지.

inserter(), back_inserter(), front_inserter()는 각각 insert_iterator, back_insert_iterator, front_insert_iterator 를 생성하는데, back_insert_iterator 의 구현을 살펴보면,

template<class _Container>
class back_insert_iterator : public _Outit
{    // wrap pushes to back of container as output iterator
public:
    explicit back_insert_iterator(_Container& _Cont)
        : container(&_Cont)
    {    // construct with container
    }

    back_insert_iterator<_Container>& operator=(
        typename _Container::const_reference _Val)
    {    // push value into container
        container->push_back(_Val);
        return (*this);
    }

protected:
    _Container *container;    // pointer to container
};

operator = 오버로딩해서 push_back을 호출한다. preincrement, postincrement, dereference 연산자는 반복자와 같은 동작을 한다.

참고