Game Develop

[C++] Iterator (반복자) 본문

C++/C++

[C++] Iterator (반복자)

MaxLevel 2022. 11. 2. 00:32

STL 컨테이너들은 내부적으로 Iterator가 있다.

컨테이너에 있는 원소들을 탐색하기 위한 포인터같은 객체로써, 각각의 컨테이너들은 탐색하는 방식(알고리즘)이 다르기 때문에 Iterator도 여러 종류가 있다.

 

입력 반복자 (input iterator) : 읽기만 가능, 순방향 이동, 현 위치의 원소를 한 번만 읽을 수 있는 반복자

출력 반복자 (output iterator) :  쓰기만 가능, 순방향 이동, 현 위치의 원소를 한 번만 쓸 수 있는 반복자 

순방향 반복자 (forward iterator) : 읽기/쓰기 모두 가능, 순방향 이동(++)이 가능한 재할당될 수 있는 반복자

양방향 반복자 (bidirectional iterator) : 읽기/쓰기 모두 가능, 순/역 방향 이동(--)이 가능한 반복자 

임의 접근 반복자 (Random access iterator) : 읽기/쓰기 모두 가능, 임의 접근                                                                                                                                                양방향 반복자 기능에 +, -, += , -=, [] 연산이 가능

 

 

 

우리가 자주 쓰는 vector는 임의접근반복자다. 임의의 접근이 가능하기 때문이다. (메모리에 연속적할당으로 인해 임의의 위치를 메모리주소값계산을 통해 바로 알아낼 수 있으니까)

그렇기 때문에 []연산도 지원하는것이다.

 

보통 컨테이너를 순회하기 위해 iterator를 이용해서 순회할 때, end()를 사용하는 경우가 있을것이다.

end()는 컨테이너의 끝원소를 가리키는 iterator가 아니라, 그 다음을 가리킨다. 그렇기 때문에 한번 이동시켜줘야된다.

그렇기 때문에 만약 iterator를 이용해서 끝원소를 얻고 싶다면

 

vector<int> temp = {1,2,3,4,5};

int endElement = *(--temp.end())  

 

이런식으로 역참조연산을 해서 값을 가져오면 된다.

erase()같은 경우, 해당 iterator위치의 원소를 삭제 후, 다음 원소의 iterator를 가리키기 때문에 루프 한번마다 iterator++을 하는 반복문의 경우, erase를 수행 후에 ++해주면 안된다.

 

저런 iterator에 --연산하는것도, 양방향으로 탐색이 가능하기 때문이다. vector라던가 deque가 해당된다.

forward_list같이 단방향일 경우 --연산을 지원하지 않는다.

 

그리고 vector에서 iterator를 통해 값을 보관할 때 주의할 점이 있다.

벡터는 capacity이상의 원소를 삽입하려 할 경우, 메모리를 '재할당'한다. 

원소삽입전과 메모리주소가 아예 바뀌어버린다는것이다.

 

vector<int> v = { 1,2 };
cout << "v의 capacity : " << v.capacity() << "  v[0]의 주소 : "<< &v[0] << endl;
v.push_back(3);
cout << "v의 capacity : " << v.capacity() << "  v[0]의 주소 : " << &v[0] << endl;

 

 

 

capacity가 2였을 때 3이라는 원소를 집어 넣음으로써 메모리가 재할당되어 capacity가 3이 되었고, 그에 따라 똑같이 첫번째 원소를 가리키고 있었을 뿐인데 주소가 바뀌었다.

그렇기때문에 아래와 같은 코드도 에러가 발생한다.

 

vector<int> v = { 1,2 };
vector<int>::iterator iter = v.begin();
cout << *iter << endl;
v.push_back(3);
cout << *iter << endl;

 

메모리 재할당후에도 이미 사라진 주소를 역참조했기 때문에 nullptr참조 오류가 뜬다.

물론 list같은 경우는 삭제한 원소를 역참조하는거 아니면 그럴일은 없다.

'C++ > C++' 카테고리의 다른 글

[C++] memcpy 사용해서 char배열 복사  (0) 2022.11.19
[C++] erase()와 iterator  (1) 2022.11.15
[C++] vector  (0) 2022.11.01
[C++] map에서 원소 넣을때 insert도 활용하자.  (0) 2022.10.29
[C++] String 성능에 관하여  (0) 2022.10.26