Стирание элемента контейнера с помощью итераторов - PullRequest
3 голосов
/ 20 декабря 2010

В моем текущем домашнем задании я создал класс итератора для списка.Я застрял в создании хорошей 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 s членам.Однако, если элемент не находится в этих позициях, то у меня (казалось бы) нет другого выбора, кроме как напрямую нарушить инкапсуляцию и изменить pCurr_ (элемент списка).

Есть ли способ избежать этого?Я заглянул внутрь списка STL, но они использовали некоторые другие функции _Next_Node_(/* stuff */) и _Prev_Node_(/* stuff */), которые были мне не очень полезны.Поиски в Google дают мне полезные результаты о том, как использовать функцию стирания, а не о том, как написать ее самостоятельно.

Вопрос: Есть ли способ, которым я могу стереть элемент, на который указывает мой итератор, без необходимости братьчлен pCurr_?

Ответы [ 2 ]

3 голосов
/ 20 декабря 2010
  1. Не используйте идентификаторы, начинающиеся с подчеркивания, за которым следует заглавная буква.Они зарезервированы для стандартных библиотечных и системных авторов.Хотя вы пишете свой собственный класс списка, вы на самом деле не пишете стандартную библиотеку.

  2. end () - это обычно один элемент после конца списка, а не последний элемент.(Чтобы получить фактический последний итератор списка, вы можете выполнить l.rbegin (). Base (), как это происходит).

  3. Передать итератор по значению, а не по неконстантной ссылке.

  4. Почему вы так обеспокоены изменением pCurr?

2 голосов
/ 20 декабря 2010

Это на самом деле не нарушает инкапсуляцию. Это почти неизбежно, что контейнер и его итераторы тесно связаны между собой. Вместе они скрывают детали реализации от пользователя. Если бы они не были друзьями друг другу, пользователю пришлось бы сообщить больше подробностей реализации. Ключевое слово friend может улучшить инкапсуляцию, если у рассматриваемых классов есть веские основания знать о внутренних компонентах друг друга.

Обратите внимание, что begin() == end(), представляющий список с одним элементом, не является стандартным соглашением библиотеки, где это означает, что контейнер пуст. end() должен возвращать итератор для "одного за концом" контейнера.

...