Insert с иттератором

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Аватара пользователя
Сионист
Сообщения: 1211
Зарегистрирован: 31 мар 2014, 06:18

Пусть есть некоторый класс контейнера, а в нём класс иттератора и функция-член Insert, принимающая иттератор элемента, после которого должна вставить новый элемент. Предположим, функция вызвана от одного члена контейнера, а иттератор принадлежит другому. То есть:

Код: Выделить всё

TContaner c1, c2;
TContaner::itterator Itterator;
...
Itterator=c2.Begin();
++Itterator;
c1.Insert(Itterator, 21);
, где TContaner - некоторый класс контейнера. Опишите правильное поведение функции-члена Insert для этого случая. Как его реализовать?
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Я бы сделал так: пробегаем контейнер, пытаясь найти в нём поинтер, инкапсулированный в итераторе. Если находим, то вставляем новый элемент после него. Если не находим - то исключение.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Сионист
Сообщения: 1211
Зарегистрирован: 31 мар 2014, 06:18

Сложноват Insert для дерева/списка получается. И слишком тормознутый. Для массива ещё ладно, вычесть адрес нулевого элемента и сравнить с количеством.
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Ну в данной реализации, которую предложил WinMain, можно и проще. Там ведь итератор содержит указатель на контейнер. Достаточно сравнить адреса и можно уже кидаться исключением, если не совпадают.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Сионист
Сообщения: 1211
Зарегистрирован: 31 мар 2014, 06:18

О какой реализации речь?
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

О реализации вот из этой темы. Сообщение №8.

Вот поэтому мне и не нравится, что ты генерируешь на каждый чих новую тему. Писал бы о самописном классе с итератором в одной теме - было бы понятно по контексту о какой реализации речь.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Сионист
Сообщения: 1211
Зарегистрирован: 31 мар 2014, 06:18

Код: Выделить всё

class Iterator
    {
    public:
        Iterator() : m_node(nullptr)
        {
        }
        Iterator(Node *n)
        {
            m_node = n;
        }
        void operator++()
        {
            if (m_node != nullptr)
            {
                m_node = m_node->Next;
            }
        }
        bool operator!=(const Iterator& it)
        {
            return (m_node != it.m_node);
        }
    private:
        Node *m_node;
    };
. Ну и где здесь в итераторе инфа о контейнере?
Писал бы о самописном классе с итератором в одной теме - было бы понятно по контексту о какой реализации речь.
Ровно столько же. О том, что речь о какой то реализации в одной из моих тем, как раз было понятно и так. Вот только ни в одной из них мне не попадались реализации с указанной особенностью.
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
Аватара пользователя
Сионист
Сообщения: 1211
Зарегистрирован: 31 мар 2014, 06:18

Что именно бросать в каждом случае:

Код: Выделить всё

class TList
{
 public:
 class TItem;
 class Iterator
 {
  private:
   friend class TList;
   friend class TItem;
   TList *Owner;
   TItem *Pointer;
   Iterator (TList *Owner, TItem *Pointer)
   {
    this->Owner  =Owner;
    this->Pointer=Pointer;
   }
  public:
   Iterator ()
   {
    Owner  =nullptr;
    Pointer=nullptr;
   }
   Iterator operator ++()
   {
    if (Owner==nullptr)
    {
     throw;
    }
    if (Pointer!=nullptr)
    {
     Pointer=Pointer->Next;
    }
    return *this;
   }
   int &operator * ()
   {
    if (Owner==nullptr)
    {
     throw;
    }
    if (Pointer==nullptr)
    {
     throw;
    }
    return Pointer->Data;
   }
   bool operator != (const Iterator &Right)
   {
    if ((Owner==nullptr)||(Right.Owner==nullptr))
    {
     throw;
    }
    return ((Owner==Right.Owner)&&(Pointer!=Right.Pointer));
   }
 };
 class TItem
 {
  friend class TList;
  friend class Iterator;
  private:
   TItem *Next;
  public:
   int Data;
 };
 private:
  TItem *First;
  TItem *Last;
 public:
  TList()
  {
   First=nullptr;
   Last =nullptr;
  }
  ~TList()
  {
   TItem *Next;
   for (Next=First->Next; Next!=nullptr; First=Next, Next=First->Next)
   {
    delete First;
   }
   Last=nullptr;
  }
  Iterator Insert (const Iterator &After, const int &Data)
  {
   TItem *Item;
   if (After.Owner==nullptr)
   {
    throw;
   }
   if (After.Owner!=this)
   {
    throw;
   }
   Item=new TItem;
   Item->Data=Data;
   if (After.Pointer==nullptr)
   {
    if (Last!=nullptr)
    {
     Last->Next=Item;
    }
    Last=Item;
    Item->Next=nullptr;
   }
   if (First==nullptr)
   {
    First=Item;
   }
   return Iterator(this, Item->Next);
  }
  Iterator Begin()
  {
   return Iterator(this, First);
  }
  Iterator End ()
  {
   return Iterator(this, nullptr);
  }
  Iterator Find(const int &Value)
  {
   TItem *Item;
   for (Item=First; Item!=nullptr; Item=Item->Next)
   {
    if ((Item->Data)==Value)
    {
     return Iterator(this, Item);
    }
   }
   return Iterator(this, nullptr);
  }
};
?
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Сионист писал(а):Ну и где здесь в итераторе инфа о контейнере?
Да, действительно нет. Значит мне показалось.
Сионист писал(а):Что именно бросать в каждом случае
Можно сделать свой класс-исключение и везде бросать его. Класс сделать вложенным, как и класс-итератор. WinMain уже давал пример, в котором был объявлен класс-исключение, который наследовался от std::exception.

Есть ещё замечание по коду. Везде делать проверку if (Owner==nullptr) и кидать исключение, не нужно. Достаточно сделать эту проверку в конструкторе итератора, ведь дальше Owner нигде в коде не меняется. И, кстати, этот факт можно подчеркнуть, объявив поле вот так:

Код: Выделить всё

TList *const Owner;
или вообще сделать ссылкой.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Вариант моего контейнера с исключениями находится в этой теме.
Из-за того, что обсуждение одного по сути вопроса разнесено на множество тем форума, нарушается целостность контекста обсуждения. Потом сложно будет собрать воедино все предложения по данной теме или появится множество повторяющихся постов от разных участников.
Ответить