본문 바로가기

C++ Programming/STL

반복자의 종류

반복자는 컨테이너 안에 저장된 원소들을 차례대로 순환할 수 있는 객체이다.

입력 반복자 - 전방향 읽기 istream
출력 반복자 - 전방향 쓰기 ostream, inserter
전방향 반복자 - 전방향 읽기, 쓰기 
양방향 반복자 - 전방향, 역방향 읽기, 쓰기 - list,set,multiset,map,multimap
랜덤 액세스 반복자 - 랜덤 액세스 - vector,deque,string,array

1. 입력 반복자 - 오로지 원소를 전진 방향으로만 읽기 액세스할 수 있는 반복자이다. 
                       한번에 한개의 원소만을 읽어들일 수 있다는 사실이다. 

2. 출력 반복자 - 오로지 원소를 전진 방향으로만 쓰기 액세스할 수 있는 반복자이다. 
                       동일한 범위에 대해서 두 번 이상 반복자를 사용하여 순회할 수 없다. 
                       첫번째 단어 이후에 나오는 두 번째 단어를 덮어쓰기보다는 차례대로 출력한다. 
3. 전방향 반복자 - 입력반복자 + 출력반복자 
   ex) 출력반복자는 비교 동작을 지원하지 않기 때문에 시퀀스의 끝을 나타내는 반복자와 비교를 할 수 없다. 
         while(true){
            *pos = foo();
            ++pos;
           }
         전방향반복자는 end()일 경우를 참조할 수 있기 때문
          while(pos != coll.end()){
              *pos = foo();
              ++pos;
          } 

4. 양방향 반복자 - 원소를 역순으로 순회할 수 있는 기능을 추가한 전방향 반복자
5. 랜덤 액세스 반복자 - +.-와 같은 반복자 연산자를 제공할 뿐만 아니라 오프셋을 더하거나 뺄 수도 있고,
                                 <,>연산자를 사용하여 두 반복자를 비교할 수 도 있다. 
                                 랜덤 액세스를 제공하는 컨테이너(vector,deque), 스트링(string,wstring), 
                                 기본의 배열(array,pointer)


ex)
     vector<int> coll;
      for(int i=-3;i<=9;++i){
           coll.push_back(i);
        }

//총 몇개의 원소를 가지고 있는지 출력한다.
cout << "number/distance: " << coll.end() - coll().begin() << endl;

//모든 원소를 출력한다.
// 주의 : != 연산자 대신 < 연산자를 사용한다.

vector<int>::iterator pos;
for(pos=coll.begin();pos<coll.end();++pos){
      cout << *pos << '';
}
cout << endl;

//모든 원소를 출력한다.
for(int i=0;i<coll.size();++i){
   cout<<coll.begin()[i] << '  ';
   }
 cout << endl;

//모든 두번째 원소를 출력한다.
 // += 연산자를 사용한다.
for(pos=coll.begin();pos<coll.end()-1;pos+=2){
      cout << *pos << '';
}
 cout << endl;

//list,set,map처럼 랜덤 액세스 반복자를 사용하지 않는 컨테이너에 대해서는 동작하지 않는다.
//루프의 종료 조건으로 제공된 < 연산자는 오직 랜덤 액세스 반복자만이 가능하다는 사실을 기억해두자.
//vector, deque, string, array

6. vector 반복자의 증,감소 문제

std::vector<int> coll;
if(coll.size() > 1) {
          sort(++coll.begin(),coll.end()); // 컴파일 에러
 }

//원인은 vector의 반복자의 구현을 일반적인 포인터처럼 구현하였기 때문이다.


7. 보조 반복자 함수
   a) advance() 함수는 인자로 전달된 값만큼 반복자의 위치를 증가시킨다.
       주의사항은 이동한 위치가 end()를 넘는지 검사하지 않는다. 
    
   ex) list<int> coll;
         list<int>::iterator pos = coll.begin();
         advance(pos,3); //pos의 위치를 3만큼 전진시킨다. 

   b) distance() 함수는 두 반복자의 위치 차이를 계산하기 위해서 제공된다.
       주의사항은 같은 컨테이너의 반복자이어야 한다. 

       list<int>::iterator pos;
       pos = find(coll.begin(),coll.end(),5);
       if(pos != coll.end(){
           cout << distance(coll.begin(),pos) <<endl;
        }

   c) iter_swap()함수는 두 반복자가 가리키고 있는 값을 교체하는 기능을 제공한다.
       반복자가 같은 타입일 필요는 없다, 가리키는 값이 할당될 수 있어야 한다.
       //첫번째, 두번째 값을 교환한다.
       iter_swap(coll.begin(),++coll.begin());

8. 역방향 반복자
    rbegin()은 역방향 반복자의 첫 번째 원소의 위치를 반환한다. 따라서 정상적인 순서로 본다면 마지막 원소의 위치를
    반환한다.
    rend()는 역방향 반복자의 마지막 원소의 위치를 반환한다. 따라서 정상적인 순서로 본다면 첫번째 원소의 
    앞 위치를 반환한다.
    역방향 반복자 디자이너들은 한 가지의 트릭을 사용하였다. 역방향 반복자에 의해서 정의되는 새로운 범위를
    정의한 것이다. 첫 번째 위치에서는 원소를 포함하지 않고 마지막 위치에서 원소를 포함한다.


              base()를 사용하여 역방향 반복자를 일반 반복자로 전환하기 
              //반복자를 역방향 반복자로 변경한다.
              list<int>::reverse_iterator rpos(pos);
              list<int>::iterator rrpos;
              //역방향 반복자를 반복자로 변경한다.
              rrpos = rpos.base();

  9. 삽입 반복자
      a) 후위 삽입 반복자 
        -  컨테이너의 push_back()멤버함수는 호출하여 컨테이너의 끝부분에 값을 추가시킨다. vector,deque,list,string
           back_inserter()
           vector <int> coll;
           1) back_insert_iterator<vector<int>> iter(coll);
               *iter = 44;
           2) back_inserter(coll) = 44;
      b) 전위 삽입 반복자
        - 컨테이너의 push_front()멤버함수를 호출하여 컨테이너의 앞부분에 값을 추가시킨다. deque,list
           list<int> coll;
           1) front_insert_iterator<list<int>> iter(coll);
              *iter = 1;
           2) front_inserter(coll) = 44;
      c) 일반적인 삽입 반복자 
           set<int> coll;
          1) insert_iterator<set<int>> iter(coll,coll.begin());
              *iter = 1;
          2) inserter(coll,coll.end()) = 45;

10. 스트림 반복자
     1) 출력 스트림 반복자 
         ostream_iterator <int> intWriter(cout,"\n");
         *intWriter = 42;
         copy(coll.begin(),coll.end(), //구별자없이 모든 원소를 기록한다.
                  ostream_iterator<int>(cout));
         copy(coll.begin(),coll.end(), //"<" 구별자를 사용하여 모든 원소를 기록한다.
                  ostream_iterator<int>(cout,"<"));
         42
         123456789
         1<2<3<4<5<6<7<8<9

     2) 입력 스트림 반복자
         istream_iterator<int> intReader(cin); //cin으로부터 정수 타입을 읽어들이는 입력 스트림 반복자 생성
         istream_iterator<int> intReaderEOF; //"끝 스트림 반복자" 생성
         while(intReader != intReaderEOF){
             cout <<"once: " <<*intReader <<endl;
             ++intReader;
          }