[C++] STL List erase member function 사용 시 주의점

    반응형

    * 다음 포스팅은 STL List Container의 erase 멤버 함수를 사용 시 발생할 수 있는 오류에 대해 다룹니다.

    * 개인적인 공부 내용을 기록하는 용도로 작성한 글 이기에 잘못된 내용을 포함하고 있을 수 있습니다.

     

    Related

    → STL List Container 사용 방법 정리


    Content

    #1 Vector erase member function

    #2 List erase member function


    #1 Vector erase member functon 

    STL 대부분의 Container는 지정된 iterator 위치의 원소를 삭제하는 erase 멤버 함수를 제공합니다.

    이는 list 뿐 만 아니라 vector container 또한 erase 멤버 함수를 포함하고 있습니다.

    다음은 1, 2, 3, 4, 5 를 원소로 가지는 int형 vector 에서 iterator로 원소 1을 가리키게 한 뒤, erase 멤버 함수를 사용해 제거한 예시입니다.

    #include <iostream>
    #include <vector>
    using namespace std;
    int main(){
    	vector<int> vec {1, 2, 3, 4, 5};
    	cout << "Before - ";
    	for(const auto& i : vec){
    		cout << i << " ";
    	}
    	cout << '\n';
    	
    	// iterator를 사용해 vector의 첫 번째 원소인 1을 가리키게 합니다.
    	vector<int>::iterator it = vec.begin();
    	cout << "It → " << *it << '\n';
    	// erase member function을 사용해 iterator it이 가리키는 원소 1을 제거합니다.
    	vec.erase(it);
    	cout << "After - ";
    	for(const auto& i : vec){
    		cout << i << " ";
    	}
    	cout << '\n';
    	return 0;
    }
    [Result]
    Before - 1 2 3 4 5
    It → 1
    After - 2 3 4 5

     

    여기서 의문이 하나 생깁니다. 그렇다면 vector의 첫 번째 원소 1을 가리키고 있던 iterator는 현재 어떤 위치를 가리키게 될까요?

    위에서 제시한 예시 코드에서 다음 한 줄을 추가해 현재 iterator가 가리키고 있는 값을 출력해 보도록 하겠습니다.

    cout << "It → " << *it << '\n';
    [Result]
    Before - 1 2 3 4 5
    It → 1
    After - 2 3 4 5
    It → 2

     

    iterator는 자동으로 vector의 다음 원소를 가리키게 됩니다.


    #2 List erase memeber function

    이번에는 List Container에서 erase member function을 사용해 보도록 하겠습니다.

    #include <iostream>
    #include <list>
    using namespace std;
    int main() {
      list<int> myList{1, 2, 3, 4, 5};
      cout << "Before - ";
      for (const auto &i : myList) {
        cout << i << " ";
      }
      cout << '\n';
    
      // iterator를 사용해 list의 첫 번째 원소인 1을 가리키게 합니다.
      list<int>::iterator it = myList.begin();
      cout << "It → " << *it << '\n';
      // erase member function을 사용해 iterator it이 가리키는 원소 1을 제거합니다.
      myList.erase(it);
      cout << "After - ";
      for (const auto &i : myList) {
        cout << i << " ";
      }
      cout << '\n';
    
      cout << "It → " << *it << '\n';
      return 0;
    }
    [Result]
    Before - 1 2 3 4 5 
    It → 1
    After - 2 3 4 5 
    It → 1

     

    vector와 달리 list의 iterator가 가리키는 값은 전혀 엉뚱한 값이 출력됩니다.

    iterator가 이미 지워진 원소인 1의 주소를 참조하고 있는 것을 확인할 수 있습니다.

     

    C++ STL list의 공식 문서의 Return Value 부분을 보면 다음과 같이 설명합니다.

    Iterator following the last removed element.

    - 마지막으로 제거된 원소의 다음 원소를 리턴합니다.

     

    즉, list에서 erase 함수를 사용할 시 vector와 달리 이터레이터로 다음과 같이 리턴값을 받아 주어야 합니다.

      // erase member function을 사용해 iterator it이 가리키는 원소 1을 제거합니다.
      it = myList.erase(it);

     

    이제 다시 코드를 실행해 보도록 하겠습니다.

    #include <iostream>
    #include <list>
    using namespace std;
    int main(){
    	list<int> myList {1, 2, 3, 4, 5};
    	cout << "Before - ";
    	for(const auto& i : myList){
    		cout << i << " ";
    	}
    	cout << '\n';
    	
    	// iterator를 사용해 list의 첫 번째 원소인 1을 가리키게 합니다.
    	list<int>::iterator it = myList.begin();
    	cout << "It → " << *it << '\n';
    	// erase member function을 사용해 iterator it이 가리키는 원소 1을 제거합니다.
    	it = myList.erase(it);
    	cout << "After - ";
    	for(const auto& i : myList){
    		cout << i << " ";
    	}
    	cout << '\n';
    	
    	// 추가된 코드
    	cout << "It → " << *it << '\n';
    	return 0;
    }
    [Result]
    Before - 1 2 3 4 5
    It → 1
    After - 2 3 4 5
    It → 2

    이터레이터가 삭제된 원소 1이 아닌 2를 가리키고 있습니다.

     

    이처럼 list container에서 erase 함수를 사용할 경우 반드시 iterator로 리턴값을 받아 주어야 합니다.

    그렇지 않으면 iterator가 엉뚱한 값을 가리키게 되어 segmentation fault 와 같은 에러를 발생시킬 수 있습니다.


    이번 포스팅 에서는 list container 에서 erase 함수를 사용 시 유의해야할 점에 대해서 살펴 보았습니다.

    도움이 되셨다면 하단의 공감 한 번씩 부탁드립니다!

    반응형

    댓글

    Designed by JB FACTORY