제목은 거창하지만(…), C++에서 흔히 사용되는 포인터의 추상화만 해도,
정도가 존재 한다. 이 외에도 policy-based smart pointer인 loki 의 스마트 포인터나 ace library의 스마트 포인터도 있고…
일단 거기에서 일단 이 글에서 설명하려는 것은 iterator — 특히 이 앞 글에서 사용했던 output iterator 를 중심으로 설명하겠다. STL에 있는 iterator는 그 용도(=특성)에 따라 총 5종류가 존재하는데, instance를 it일 때 연산들을 설명해보면,
우선 가장 제한적인 iterator 두 종류.
이 두 가지는 it++ 같은 연산의 타입이 void 인 경우가 대부분이고 — 즉 위치를 바꾸기만 하면 된다는 것 — 진행하고 나서 되 돌아가는 일이 없다 (=단방향으로 움직인다). 둘 다 [시작, 끝) 영역에 대해서 읽거나/쓰는데 중점을 두는 것인데, 이 앞 글에서 썼던,
std::set_intersection( A.begin(), A.end(), B.begin(), B.end(), OutputIteratorInstance );
같은 연산에서 "결과/출력 값을 쓰기 위해" 사용된다. 이 녀석을 실제로 구현할 때 필요한 연산은 몇 개 없는데,
정도의 가정/연산이 있으면 그만. *it 에서 반환하는 타입은 굳이 정의될 필요는 없는데, 흔히 일종의 proxy-type을 두고, 거기에 필요한 = 연산자를 타입별로 오버로딩한다 — 심지어 템플릿을 쓰기도 한다(…).
가장 흔하게 보게되는 애는 아마,
back_inserter( some_vector );
일 것 같은데, A, B가 set<int> 같은 녀석이면,[1]
vector<int> c;
set_intersection( A.begin(), A.end(), B.begin(), B.end(), back_inserter(c));
같이 쓰면 교집합한 결과가 c에 저장된다. 혹은 저 값을 저장해서 쓸 게 아니라 콘솔로 출력한다면, 그런 대로 자주 보게되는 ostream_iterator 라는 녀석을 써서
set_intersection( A.begin(), A.end(), B.begin(), B.end(), ostream_iterator<int>( cout ) );
이런 함수를 통해 cout 으로 뿌려댈 수 있다. 근데 이런 연산으로 부족하다면, 위에서 설명한 output-iterator 의 조건을 만족하는 클래스를 짜버리면 된다. 예를 들어 제곱값을 출력하는(…) output-iterator는 다음처럼 정의할 수 있다.
struct FunctorOutputIterator
{
FunctorOutputIterator() {};
FunctorOutputIterator( const FunctorOutputIterator& rhs ) {} ;
void operator++(int) { }
inline FunctorOutputIterator& operator++() { return *this; };
struct Contain
{
inline Contain& operator=( const int x )
{
cout << x*x << " " << endl;
return *this;
}
} m_Con;
inline Contain& operator*() { return this->m_Con; }
};
살짝 길긴한데, Contain 이라는 proxy를 통해서 대입 연산자를 제공하고, 이걸 통해서 "대입한다는 개념"을 덮어써서 제곱값을 출력하게 했다.[2]
즉, duck-typing 스럽게[3] 추상화된 포인터인 C++의 iterator를 "따라 구현해서" 공간 낭비 없이 STL 특유의 효율적인 알고리즘을 쉽게 사용할 수 있게 해준다. 이런 식의 일반화 프로그래밍도 좀 공부해보면 – 특히 STL의 algorithm, iterator의 철학을 익히고, 그리고 boost의 lambda, function, functional 를 좀 써보면 — 괜찮은 코드를 별 타입문제 없이(=duck-typing!) 쉽게쉽게 쓸 수 있게된다
References
항목 26: const_iterator나 reverse_iterator, const_reverse_iterator도 좋지만 역시 쓸만한 것은 iterator이다... 내가 STL에 조예가 깊어서 글을 남기는 것이 아니라, Effecitve STL 을 ...
Pingback from 최익필의 이름없는 블로그 on July 26, 08 at 9:51pm
Jump to comments