반복자

-> 포인터와 사용 방법이 동일하지만 포인터가 아닌 단순 객체이다.

-> 연산자 오버로딩을 통해 포인터를 사용 하듯 사용하면 된다.

 

컨테이너마다 원소를 순회하는 방법이 다르다.

-> 하지만 반복자를 이용하면 순회 방법이 획일화 된다.

 

 

반복자 선언

-> 각 컨테이너 내부에 구현되어 있다.

-> 스코프 연산자를 통해서 접근한다.

1
vector<int>::iterator Iter;
cs

 

front와 back

front : vector의 첫 번째 원소에 접근

back : vector의 마지막 원소에 접근

 

반복자의 초기화

-> 컨테이너가 반복자를 반환하게 하면 된다.

 

반복자를 초기화하기 위해 대입을 시도하게 되는데,

여기서 대입 연산자 기준 좌측은 객체이기 때문에

객체 타입을 통해서 초기화를 진행해야 한다.

 

vector.front와 vector.back은 int형 이므로 타입이 달라 불가능하다.

하지만 vector안에 begin()과 end()라는 함수가 존재한다.

 

begin() : 첫 번째 원소의 위치를 가리키는 반복자를 반환

end() : 마지막 원소 다음 위치를 가리키는 반복자를 반환

1
2
vector<int>::iterator Iter_begin = vecInt.begin();
vector<int>::iterator Iter_end = vecInt.end();
cs

 

반복자를 통한 원소 순회

1
2
3
4
for(; Iter_begin != Iter_end; ++Iter_begin)
{
   cout << *Iter_begin << endl;
}
cs

 

반복자의 종류

임의 접근 반복자, 양 방향 접근 반복자, 순 방향 접근 반복자, 입력 반복자, 출력 반복자

 

#1. 임의 접근 반복자

-> 배열 기반 컨테이너들이 가지는 반복자이다.

++, --, [], +=, -=

1
2
3
4
5
6
vector<int>::iterator Iter_begin = vecInt.begin();
 
++Iter_begin;
--Iter_begin;
Iter_begin[4];
Iter_begin+= 4;
cs

#2. 양 방향 접근 반복자

-> 노드 기반 컨테이너들이 가지는 반복자이다.

++, --

1
2
3
4
vector<int>::iterator Iter_begin = vecInt.begin();
 
++Iter_begin;
--Iter_begin;
cs

 

vector의 중간 삽입

insert()

1
2
3
4
5
6
7
8
9
10
11
12
13
vector<int> vecInt;
vecInt.push_back(1);
vecInt.push_back(2);
vecInt.push_back(3);
vecInt.push_back(4);
 
vector<int>::iterator iter_begin = vecInt.begin();
vector<int>::iterator iter_begin = vecInt.end();
 
iter_begin += 2;
 
vecInt.insert(iter_begin, 999);
vecInt.insert(iter_begin, 9999);
cs

 

중간 삽입 후 확인 방법 두 가지

 

#1. 배열 형식

1
2
3
4
for(size_t i = 0; i < vecInt.size(); ++i)
{
    cout << vecInt[i] << endl;
}
cs

#2. 반복자 형식

1
2
3
4
5
for(; iter_begin != iter_end; ++iter_begin;)
{
   cout << *iter_begin << endl;
}
 
cs

반복자 형식에서 실행을 하면 메모리 누수가 발생한다.

이것을 '반복자의 무효화'라고 한다.

 

반복자의 무효화

원소를 삽입하면 개수가 달라지면서 end의 위치가 변하게 된다.

반복자의 위치가 변하게 될 경우 반복자의 무효화가 발생한다.

 

메모리 개수를 초과하는 삽입의 시도가 있을 경우 재할당 및 복사가 발생한다.

재할당을 하는 순간 begin 또한 위치가 무효화된다.

 

그렇기 때문에 메모리 개수를 초과하는 삽입의 시도가 있을 경우

반복자 초기화를 해줘야 한다.

1
2
3
4
5
6
7
8
iter_begin = vecInt.begin();
iter_end = vecInt.end();
 
for(; iter_begin != iter_end; ++iter_begin)
{
   cout << *iter_begin << endl;
}
 
cs

 

중간 삭제

erase()

 

#1. 일반적인 방법

1
2
3
4
5
6
7
8
9
10
11
12
13
14
vector<int> vecInt;
vecInt.push_back(1);
vecInt.push_back(2);
vecInt.push_back(3);
vecInt.push_back(4);
 
vector<int>::iterator iter_begin = vecInt.begin();
vector<int>::iterator iter_end   = vecInt.end();
 
++iter_begin();
++iter_begin();
 
vecInt.erase(iter_begin);
iter_begin = vecInt.begin();
cs

#2. 대입을 통한 중간 삭제

1
2
3
4
5
6
7
8
9
10
11
12
13
vector<int> vecInt;
vecInt.push_back(1);
vecInt.push_back(2);
vecInt.push_back(3);
vecInt.push_back(4);
 
vector<int>::iterator iter_begin = vecInt.begin();
vector<int>::iterator iter_end   = vecInt.end();
 
++iter_begin();
++iter_begin();
 
iter_begin = vecInt.erase(iter_begin);
cs

일반적인 방식으로 중간 삭제를 시도하면 값은 1,2,4가 나오게 되는데,

대입을 통해서 중간 삭제를 하게되면 값이 4만 나오게 된다.

 

이유는 기존에 begin의 위치에 있던 값이 삭제 되었기 때문이다.

begin의 위치에 있던 값이 삭제가 되면 begin은 삭제 된 값의 바로 뒤에 위치하게된다.

만약 일반적인 방식과 같은 값을 출력하고 싶다면,

begin을 다시 초기화 해주면 된다.

1
2
3
iter_begin = vecInt.erase(iter_begin);
 
iter_begin = vecInt.begin();
cs

중간 삭제에서는 반복자 end는 따로 필요없기 때문에

반복자 begin만 초기화를 해줘도 상관없다.

1
2
3
4
5
6
7
8
9
10
11
vector<int>::iterator iter_begin = vecInt.begin();
 
++iter_begin;
++iter_begin;
 
iter_begin = vecInt.erase(iter_begin);
 
for(; iter_begin != vecInt.end(); ++iter_begin)
{
    cout << *iter_begin << endl;
}
cs

 

'Programming > STL' 카테고리의 다른 글

C++(STL Container) vector의 메모리 정책, 생성자, reserve()  (1) 2020.09.28
C++(STL Container) 조건자(algorithm)  (0) 2020.09.28
C++(STL Container) vector  (0) 2020.09.27
C++(STL Container) map  (0) 2020.09.27
C++(STL Container) list  (0) 2020.09.27

+ Recent posts