ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 2024.02.29 - iterator
    C++ 2024. 3. 3. 22:08

    반복자(iterator)는 포인터와 같은 기능을 한다. 반복자는 컨테이너(vector, 배열, 등등)에 저장되어 있는 원소들을 참조할 때 사용한다. 반복자는 포인터처럼 일반적인 값이 아닌 주소값이 들어간다.

     

    • vector의 반복자 선언
    vector<int>::iterator 반복자이름;

     

    • vector의 iterator begin(), end()

    vector의 멤버 함수 begin()은 vector의 첫번째 요소의 반복자(주소값)를 반환한다. end()는 마지막 요소 +1의 반복자를 반환한다.

     

    #include<iostream>
    #include<vector>
    
    int main() {
        std::vector<int>::iterator iter;
        std::vector<int> vec = { 1,2,3,4,5 };
    
        iter = vec.begin();
        std::cout << *iter << std::endl;
    
        iter = --vec.end();
        std::cout << *iter << std::endl;
    }

     

    반복자를 역참조해서 그 주소의 값을 참조할 수 있다. 여기서 주의할 점은 end()는 vector의 마지막 요소의 주소가 아닌 그보다 한칸 더 뒤의 주소를 반환한다는 것이다. 

     

     

    • 반복자를 이용해 for문 돌리기
    #include<iostream>
    #include<vector>
    
    int main() {
        std::vector<int> vec = { 1,2,3,4,5 };
    
        for (std::vector<int>::iterator iter = vec.begin(); iter != vec.end(); iter++) {
            std::cout << *iter << std::endl;
        }
    }

     

     

    • vector의 요소 삽입, 제거 하기 (insert(), erase())
    #include<iostream>
    #include<vector>
    
    int main() {
    	std::vector<int> vec = { 1,2,3,4,5 };
    
    	std::vector<int>::iterator iter = vec.begin() + 1;
    	vec.insert(iter, 7);
    
    	for (std::vector<int>::iterator iter = vec.begin(); iter != vec.end(); iter++) {
    		std::cout << *iter << std::endl;
    	}
    }

     

    #include<iostream>
    #include<vector>
    
    int main() {
    	std::vector<int> vec = { 1,2,3,4,5 };
    
    	std::vector<int>::iterator iter = vec.begin() + 1;
    	vec.erase(iter);
    
    	for (std::vector<int>::iterator iter = vec.begin(); iter != vec.end(); iter++) {
    		std::cout << *iter << std::endl;
    	}
    }

     

    insert와 erase를 사용하면 해당 위치의 요소를 수정한뒤 다른 요소의 데이터를 일일히 한 칸 씩 옮겨준다. 그렇기 때문에 데이터의 삽입과 제거가 빈번히 일어날 경우 vector보단 배열이나 deque를 사용하는 것이 좋다.

     

     

    • 반복문 안에서 vector의 요소 삽입, 제거하기
    #include<iostream>
    #include<vector>
    
    int main() {
        std::vector<int> v = { 1,2,3,4,5 };
        std::vector<int>::iterator iter = v.begin();
        for (int i = 0; i < v.size(); i++) {
            if (v[i] == 3) v.erase(iter+i);
        }
        for (int i = 0; i < v.size(); i++) {
            std::cout << v[i] << std::endl;
        }
    }

     

    반복문을 반복자를 사용하지 않고 돌리는 경우 erase를 하더라도 문제가 생기지 않는다.

    하지만 반복자를 사용해서 반복문을 돌리는 경우 중간에서 값을 erase하면 문제가 생긴다.

     

    #include<iostream>
    #include<vector>
    
    int main() {
        std::vector<int> v = { 1,2,3,4,5 };
        for (std::vector<int>::iterator iter = v.begin(); iter != v.end(); iter++) {
            if (*iter == 3) v.erase(iter);
        }
        for (int i = 0; i < v.size(); i++) {
            std::cout << v[i] << std::endl;
        }
    }

    can't increment invalidated vector iterator. 무효화된 벡터 반복기를 증가시킬 수 없습니다. 라는 에러가 뜬다. vector의 요소를 erase한 순간 부터 그 벡터의 반복자(iter)는 무효화 되어 증가시킬수 없게 된다. 이 경우 새로운 반복자를 iter에 대입시켜 주어야 반복문을 계속 돌릴 수 있다.

     

    v.erase() 단순히 벡터 v의 요소를 지울 뿐 아니라, 지운 요소의 다음 요소의 주소값을 반환하는 기능이 있다.erase에서 반환되는 반복자 값을 iter에 대입 시켜주면 반복문이 잘 돌아간다.

     

    #include<iostream>
    #include<vector>
    
    int main() {
        std::vector<int> v = { 1,2,3,4,5 };
        for (std::vector<int>::iterator iter = v.begin(); iter != v.end(); iter++) {
            if (*iter == 3)  iter = v.erase(iter);
        }
        for (int i = 0; i < v.size(); i++) {
            std::cout << v[i] << std::endl;
        }
    }

     

    vector에 값을 삽입할 때도 비슷한 방법으로 해결할 수 있지만 주의할 점이 있다.

    #include<iostream>
    #include<vector>
    
    int main() {
        std::vector<int> v = { 1,2,3,4,5 };
        for (std::vector<int>::iterator iter = v.begin(); iter != v.end(); iter++) {
            std::cout << "for문을 영원히 돌거야..." << std::endl;
            if (*iter == 3)  iter = v.insert(iter, 7);
        }
        for (int i = 0; i < v.size(); i++) {
            std::cout << v[i] << std::endl;
        }
    }

     

    v.insert로 값 3이 있던 자리에 7을 넣고 그 다음 주소를 가리키면, 그 주소는 여전히 값3 인 곳을 가리키고 있으므로 for문을 빠져 나올 수 없다.

     

    #include<iostream>
    #include<vector>
    
    int main() {
        std::vector<int> v = { 1,2,3,4,5 };
        for (std::vector<int>::iterator iter = v.begin(); iter != v.end(); iter++) {
            if (*iter == 3)  iter = ++v.insert(iter, 7);
        }
        for (int i = 0; i < v.size(); i++) {
            std::cout << v[i] << std::endl;
        }
    }

     

    insert가 반환하는 주소값에 +1 해주어야 다음 값을 비교할 수 있다.

     

Designed by Tistory.