항목 27 : const_iterator를 iterator로 바꾸는 데에는 distance와 advance를 사용하자.
Programming/STL / 2010. 11. 3. 15:59
내가 STL에 조예가 깊어서 글을 남기는 것이 아니라, Effecitve STL 을 공부하는 사람들이 이 글을 보고, 도움이 되었으면 하는 생각과, 혹시 내가 틀린것이 있다면 지적해 주시지 않을까 란 생각으로 글을 올리는것임을 미리 밝힙니다. - 최익필
저번 26항목에서 각 iterator 간의 변환 과정을 그림(?) 으로 보여 주었었다.
const_iterator
↗ ↖
iterator ↖ base()
↘↖base() ↖
reverse_iterator → const_reverse_iterator
다시 정리 하자면,
1. 화살표 방향은 컴파일러에 의해서 암시적으로 바뀐다.(안그런 컴파일러도 있으니 해결방법은 26항목)
2. base() 는 함수이고, 명시적으로 사용자가 호출해야지만, 변환이 가능하다는 것이다.
여기서 잠깐,
혹시 iterator 를 casting 하면 되지 않을까? 란 생각을 했다면, 아직 iterator 가 어떻게 구현되었는지 분석하지 않은듯 보이는데, iterator는 .. class객체이며, 각 iterator 마다 각기 다른 class 이다. 그렇기 때문에 cating 을 해도 정상 작동하지 않는다.
본론으로 들어와서.. const_iterator ---> iterator 방향으로 변환이 되지 않는데, 어떻게 저자는 바꿀수 있다고 할수 있는가?
그 꽁수가 distance 함수와 advance 함수를 사용하는것이다. 아래 코드도 포함한다.
즉 두 같은 타입의 두 iterator를 받아 드리어, 그 사이를 리턴해 준다.
std::advace()의 인자값으러 넣은 iterator를 Off 길이 만큼 이동 시켜 준다.
자.. 두 함수의 설명은 끝났고. 이제 이 두 함수를 이용하여, const_iterator 를 iterator 로 변환해 보자. 주의해야 할것은 std::distance 는 한가지 타입의 iterator만 받는 템플릿 함수이므로 그냥 호출하면 const_iterator 를 iterator 로 변환을 시도하여, 컴파일타임 에러를 발생시킬 것이다.
그래서 명시적으로 const_iterator 라고 알려 주기만 하면 된다. 그래서 아래의 코드처럼 하면 iterator 로 변환 완료!
그런데 눈치 빠른 분들은 이런 생각을 하게 될 것이다. "이거 쓸때 없는 비용 많이 무는거 같은데..? 거리가 멀면 멀어질수록 더 느려지잖아?" .. 맞다. 역시 당신은 똑똑했다. 그래서 const_iterator 보다 iterator 를 사용하라고 26장에서 설명했던 것이다.
이것 만은 잊지 말자.
1. const_iterator 를 iterator 로 바꿀수 있다!
2. 대신 좀 시간이 걸린다. 속편히 iterator 를 사용하는것을 염두하자.
관련링크
http://lagoons.net/tt/594 <-- 깔끔한 설명
http://alones.kr/blog/626?TSSESSIONaloneskrblog=1e73a3a9327170d3301688495e6aeb41 <-- 다른 경우
저번 26항목에서 각 iterator 간의 변환 과정을 그림(?) 으로 보여 주었었다.
const_iterator
↗ ↖
iterator ↖ base()
↘↖base() ↖
reverse_iterator → const_reverse_iterator
다시 정리 하자면,
1. 화살표 방향은 컴파일러에 의해서 암시적으로 바뀐다.(안그런 컴파일러도 있으니 해결방법은 26항목)
2. base() 는 함수이고, 명시적으로 사용자가 호출해야지만, 변환이 가능하다는 것이다.
여기서 잠깐,
혹시 iterator 를 casting 하면 되지 않을까? 란 생각을 했다면, 아직 iterator 가 어떻게 구현되었는지 분석하지 않은듯 보이는데, iterator는 .. class객체이며, 각 iterator 마다 각기 다른 class 이다. 그렇기 때문에 cating 을 해도 정상 작동하지 않는다.
본론으로 들어와서.. const_iterator ---> iterator 방향으로 변환이 되지 않는데, 어떻게 저자는 바꿀수 있다고 할수 있는가?
그 꽁수가 distance 함수와 advance 함수를 사용하는것이다. 아래 코드도 포함한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
| // ikpil.com or ikpil.tistory.com // MSVC2005 distance 내부 template < class _InIt> inline typename iterator_traits<_InIt>::difference_type __CLRCALL_OR_CDECL distance(_InIt _First, _InIt _Last) { // return distance between iterators // typename 잘 썻고~ Off 선언하고~ typename iterator_traits<_InIt>::difference_type _Off = 0; // 두 인자 사이의 거리를 Off에 기록 하고 _Distance2(_First, _Last, _Off, _Iter_cat(_First)); // Off 리턴~ return (_Off); } |
즉 두 같은 타입의 두 iterator를 받아 드리어, 그 사이를 리턴해 준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| // ikpil.com or ikpil.tistory.com // MSVC2005 advance 내부 template < class _InIt, class _Diff> inline void __CLRCALL_OR_CDECL advance(_InIt& _Where, _Diff _Off) { // increment iterator by offset, arbitrary iterators // 레퍼런스로 받은 Where 을 다시 _Advace에 넣는다. _Advance(_Where, _Off, _Iter_cat(_Where)); } // MSVC2005 _Advance 내부 template < class _InIt, class _Diff> inline void __CLRCALL_OR_CDECL _Advance(_InIt& _Where, _Diff _Off, input_iterator_tag) { // increment iterator by offset, input iterators #if _HAS_ITERATOR_DEBUGGING // if (_Off < 0) // _DEBUG_ERROR("negative offset in advance"); #endif /* _HAS_ITERATOR_DEBUGGING */ for (; 0 < _Off; --_Off) // &로 받은 .. Where을 전위연산하여 Off 만큼 증가 시킨다. ++_Where; } |
std::advace()의 인자값으러 넣은 iterator를 Off 길이 만큼 이동 시켜 준다.
자.. 두 함수의 설명은 끝났고. 이제 이 두 함수를 이용하여, const_iterator 를 iterator 로 변환해 보자. 주의해야 할것은 std::distance 는 한가지 타입의 iterator만 받는 템플릿 함수이므로 그냥 호출하면 const_iterator 를 iterator 로 변환을 시도하여, 컴파일타임 에러를 발생시킬 것이다.
그래서 명시적으로 const_iterator 라고 알려 주기만 하면 된다. 그래서 아래의 코드처럼 하면 iterator 로 변환 완료!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| // ikpil.com or ikpil.tistory.com #include <deque> #include <algorithm> #include <iostream> typedef std::deque< int > Container; int main( void ) { Container Test; Test.push_back(1); Test.push_back(1); Test.push_back(1); Test.push_back(1); typedef Container::const_iterator Const_It; Const_It cit = Test.end(); // 끝을 가리키게 한다. typedef Container::iterator Nomal_It; Nomal_It it = Test.begin(); // 꼭 초기화를 해줘야 한다. // distance 는 템플릿 함수이므로 명시적으로 지정 가능하다. std::advance(it, std::distance<Const_It>(it, cit)); if ( cit == it ) // <-- 왜 cit 을 먼저 썻는지 알 것이다. std::cout << "같습니다." << std::endl; else std::cout << "다릅니다.." << std::endl; } |
그런데 눈치 빠른 분들은 이런 생각을 하게 될 것이다. "이거 쓸때 없는 비용 많이 무는거 같은데..? 거리가 멀면 멀어질수록 더 느려지잖아?" .. 맞다. 역시 당신은 똑똑했다. 그래서 const_iterator 보다 iterator 를 사용하라고 26장에서 설명했던 것이다.
이것 만은 잊지 말자.
1. const_iterator 를 iterator 로 바꿀수 있다!
2. 대신 좀 시간이 걸린다. 속편히 iterator 를 사용하는것을 염두하자.
관련링크
http://lagoons.net/tt/594 <-- 깔끔한 설명
http://alones.kr/blog/626?TSSESSIONaloneskrblog=1e73a3a9327170d3301688495e6aeb41 <-- 다른 경우
반응형
'Programming > STL' 카테고리의 다른 글
2.1 문자열을 키로 쓰는 map, set 성능 향상시키기 (0) | 2011.02.07 |
---|---|
[펌] Effective STL 읽은 후 정리~ (0) | 2011.01.05 |
부스트(boost) 관련 스프링노트 (0) | 2010.06.11 |
C++ STL int -> string, string -> int 로 변환하기 (1) | 2010.04.27 |
괜찮은 참고 사이트 (0) | 2010.04.20 |