2010-12-20 4 views
3

현재 숙제를 사용하면 목록에 대한 반복기 클래스를 만들 수 있습니다. 좋은 erase(iterator where) 함수를 만드는 데 막혔습니다.반복자를 사용하여 컨테이너 요소 지우기

현재 코드 (질문에 나타나게) 소거와

class List 
{ 
    class _Iter 
    { 
     friend class List; 
    public: 
     _Iter(ListElem *pCurr, List *pList); 

     /* *, ->, ++, --, == and != operators overloaded */ 

    private: 
     ListElem *pCurr_; List *pList_; 
    }; 

    typedef _Iter iterator; 

    iterator erase(iterator where); 
}; 

그래서 같이 구현되고 :

// Precondition: List has been checked for size > 0. 
List::iterator List::erase(List::iterator& where) 
{ 
    // Erasing only element in list. 
    if(where == end() && where == begin()) 
    { 
     pop_back(); // or pop_front(); 
     return iterator(0, this); 
    } 

    // Elem at end 
    if(where == end()) 
    { 
     pop_back(); 
     return end(); 
    } 
    else 
    { 
     // Elem at beginning 
     if(where == begin()) 
     { 
      pop_front(); 
      return ++begin(); 
     } 
    } 

    // Elem somewhere between beginning and end. 
    iterator temp(where); 
    // The node next to pCurr_ should point to the one before pCurr_ 
    where.pCurr_->next->prev = where.pCurr_->prev; 
    // The node before pCurr_ should point to the one after pCurr_ 
    where.pCurr_->prev->next = where.pCurr_->next; 
    // Return the node after pCurr_ 
    ++temp; 
    delete where.pCurr_; 
    --size_; 
    return temp; 
} 

처음 세 사례 - 유일한 요소, 처음에 최종 소자의 소자 - 괜찮아. 코드가 잘 지정되어 있고 _Iter 명의 회원에 대한 지식과 개인 액세스가 절대적으로 필요하지 않습니다. 그러나 요소가 그 위치에 없다면 캡슐화를 위반하고 pCurr_ (목록의 요소)를 직접 변경해야합니다 (겉으로는) 선택의 여지가 있습니다.

이 문제를 방지 할 수있는 방법이 있습니까? 나는 STL리스트 안을 들여다 보았다. 그러나 다른 유용한 함수 인 _Next_Node_(/* stuff */)_Prev_Node_(/* stuff */)을 사용했다. Google 검색을 사용하면 직접 지우는 방법이 아니라 지우기 기능을 사용하는 방법에 대한 유용한 결과를 얻을 수 있습니다.

질문 : iterator가 가리키는 요소를 pCurr_ 멤버를 갖지 않고 지울 수있는 방법이 있습니까?

+1

STL의 목록에는 이전 노드와 다음 노드 모두에 대한 포인터가 있으므로 _Next_Node 및 _Prev_Node_는 쓸모가 없습니다. – DumbCoder

+0

@DumbCoder : "쓸모가 없다"는 의미는 아니지만 지우기 기능 구현에 대한 이해를 돕지 못했습니다. – IAE

답변

3
  1. 밑줄로 시작하고 대문자로 시작하는 식별자는 사용하지 마십시오. 표준 라이브러리 및 시스템 작성자 용으로 예약되어 있습니다. 자신의 목록 클래스를 작성하고 있지만 실제로 표준 라이브러리를 작성하지는 않습니다.

  2. end()는 일반적으로 마지막 요소가 아닌 목록의 끝에서 하나의 요소입니다. (목록의 실제 마지막 반복자를 얻으려면 l.rbegin(). base()가 일어날 수있다).

  3. 이터레이터를 비 const 참조가 아닌 값으로 전달하십시오.

  4. 왜 pCurr 수정에 관심이 있습니까?

+0

펠트처럼 코드 냄새가 난다. 1)에 관해서는, 그건 선생님의 디자인에 의한 것이므로, 저는 그렇게해야합니다. 2)를 위해, 나는 그것을 어떻게해서든지 바꿔야 할 것이다. 그러나 예, 당신은 옳다! 3)에 대한 팁도 주셔서 감사합니다. – IAE

+0

표준 라이브러리가 아니라면 테일 반복자를 얻기위한 함수를 만들 수 있습니다. 원한다면 tail() 또는 last()를 사용할 수 있습니다.나는 C++에서 일반적인 의미를 갖는 end()를 사용함으로써 "혼동"하지 말라고 말할 것이다. – CashCow

2

이것은 실제로 캡슐화에 위배되지 않습니다. 컨테이너와 iterator가 밀접하게 결합되는 것은 불가피합니다. 두 사람은 함께 구현 세부 정보를 숨 깁니다. 그들이 서로 친구가 아니면 많은 구현 세부 사항이 사용자에게 유출되어야합니다. 친구 키워드는 캡슐화를 향상시킬 수 있습니다. 해당 클래스가 서로 내부에 대해 알만한 타당한 이유가있는 경우 캡슐화하십시오.

하나의 요소가있는 목록을 나타내는 begin() == end()은 컨테이너가 비어 있음을 나타내는 표준 라이브러리 규칙이 아닙니다. end()은 iterator를 컨테이너의 "one-past-the-end"로 반환해야합니다.

+0

end() == begin() 것은 head_ 및 tail_ 포인터를 사용하여 내 디자인을 결정한 것입니다. 나는 곧이 문제를 해결할 것이다. – IAE

관련 문제