3

My current homework assignment has me creating an iterator class for a list. I'm stuck at creating a good erase(iterator where) function.

Current code (reduced to fit question):

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);
};

with the erase being implemented like so:

// 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;
} 

The first three cases- only element, element at end and element at beginning- are all okay. Coded fine and need absolutely no knowledge and private access to _Iters members. However, if the element is not in those positions, then I have (seemingly) no choice but to violate the encapsulation and change pCurr_ (element of the list) directly.

Is there any way to avoid this? I looked inside the STL list, but they used some other functions _Next_Node_(/* stuff */) and _Prev_Node_(/* stuff */) that weren't very useful to me. Google searches give me helpful results on how to use the erase function, not how to write it myself.

Question: Is there a way in which I can erase the element pointed to by my iterator without having to grab it's pCurr_ member?

IAE
  • 2,213
  • 13
  • 37
  • 71
  • 1
    List in STL has pointers to both the previous and the next node, so _Next_Node and _Prev_Node_ arent't useless. – DumbCoder Dec 20 '10 at 14:35
  • @DumbCoder: I didn't mean useless as in, "They're useless", but rather that it wasn't helping my understanding of implementing the erase function. – IAE Dec 20 '10 at 14:45

2 Answers2

3
  1. Do not use identifiers beginning with underscore followed by an uppercase letter. They are reserved for standard library and system writers. Although you are writing your own list class, you are not actually writing the standard library.

  2. end() is normally one element past the end of the list, not the last element. (To get the actual last iterator of the list you can do l.rbegin().base() as it happens).

  3. Pass the iterator by value, not non-const reference.

  4. Why are you so concerned with modifying pCurr?

CashCow
  • 30,981
  • 5
  • 61
  • 92
  • Felt like a code smell imo. As to 1), that was by my teacher's designs, so I have to do that. For 2), I'll have to change that anyway, but yes, you are right! Thanks for the tipp on 3) too. – IAE Dec 20 '10 at 14:42
  • Given it is not the standard library you could create a function to get the tail iterator, maybe tail() or last() if you want. I would just say do not "confuse" by using end() which in C++ has a conventional meaning. – CashCow Dec 20 '10 at 17:18
2

This is not really violating encapsulation. It is pretty much inevitable that a container and its iterators are tightly coupled. The two of them together hide the implementation details from the user. If they weren't friends to each other, more implementation details would have to be leaked to the user. The friend keyword can enhance encapsulation if the classes in question have valid reasons to know about each others internals.

Note that begin() == end() representing a list with one element is not the standard library convention where it means that the container is empty. end() should return an iterator to "one-past-the-end" of the container.

visitor
  • 8,564
  • 2
  • 26
  • 15
  • The end() == begin() thing is because of my wonky design decision with my head_ and tail_ pointers. I'll fix this soon. – IAE Dec 20 '10 at 14:43