2010-12-20 110 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 */),這些功能對我來說並不是很有用。谷歌搜索給我如何使用擦除功能有用的結果,而不是如何自己寫。

問題:有沒有一種方法可以刪除我的迭代器指向的元素,而無需抓取它的pCurr_成員?

+1

STL中的列表具有指向上一個節點和下一個節點的指針,所以_Next_Node和_Prev_Node_都是無用的。 – DumbCoder 2010-12-20 14:35:06

+0

@DumbCoder:我不是毫無用處的,因爲它們「無用」,而是它不能幫助我理解實現擦除功能。 – IAE 2010-12-20 14:45:50

回答

3
  1. 請勿使用以下劃線開頭且後跟大寫字母的標識符。它們保留給標準庫和系統編寫者。儘管您正在編寫自己的列表類,但實際上並不是在編寫標準庫。

  2. end()通常是通過列表末尾的一個元素,而不是最後一個元素。 (要獲得列表的實際最後一個迭代器,可以在發生時執行l.rbegin()。base())。

  3. 按值傳遞迭代器,而不是非const引用。

  4. 爲什麼你如此關心修改pCurr?

+0

感覺像一個代碼氣味imo。至於1),那是我老師的設計,所以我必須這樣做。對於2),無論如何我必須改變它,但是,是的,你是對的!感謝3)上的提示。 – IAE 2010-12-20 14:42:11

+0

鑑於它不是標準庫,您可以創建一個函數來獲取尾部迭代器,如果需要,可以使用tail()或last()。我只是說,不要使用在C++中具有常規意義的end()來「混淆」。 – CashCow 2010-12-20 17:18:23

2

這並不是真的違反了封裝。容器和它的迭代器緊密耦合幾乎是不可避免的。他們兩人一起隱藏用戶的實施細節。如果他們不是彼此的朋友,更多的實施細節將不得不泄露給用戶。 朋友關鍵字可以增強封裝如果有問題的類有正當理由知道其他內部。

請注意,begin() == end()代表一個元素的列表不是標準庫約定,這意味着容器是空的。 end()應該將一個迭代器返回到容器的「一前一後」。

+0

end()== begin()是因爲我的head_和tail_指針的設計決定不當。我很快就會解決這個問題。 – IAE 2010-12-20 14:43:02