Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Быстрое удаление класса из std::list


Автор: GKosh 29.5.2008, 10:13
День добрый!

До сих пор удалял объекты из std::list<MyClass*> путем перебора списка. В реализации видно, что список двусторонний, то есть перебор по идее не требуется. Достаточно иметь указатель на объект списка. Насколько я понял, функцию этих указателей для пользователя в std::list играют иттераторы.

Вопрос, можно ли вставить в класс, хранящийся в списке иттератор списка, чтобы сразу вызывать erase по этому иттератору, без необходимости перебирать?

Проверил бы опытным путем, но сильно поджимает время. Если кто-то в курсе, буду очень признателен.

Автор: Alek86 29.5.2008, 10:30
да можно, если MyClass будет содержать std::list<Class*>::iterator в качестве поля
но для автоматизаци лучше сделать свой список (наследник std::list или включающий его), который при вставке будет сам заполнять это поле класса MyClass.

Автор: GKosh 29.5.2008, 11:06
Спасибо! это хорошая новость smile

Автор: Lazin 29.5.2008, 11:44
Цитата(Alek86 @ 29.5.2008,  10:30)
да можно, если MyClass будет содержать std::list<Class*>::iterator в качестве поля
но для автоматизаци лучше сделать свой список (наследник std::list или включающий его), который при вставке будет сам заполнять это поле класса MyClass.

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

решения:
можно использовать boost::intrusive, класс будет содержать в себе все необходимое, что-бы быть элементом контейнера, это сэкономит память, так-же будет меньше уровень косвенности при обращении к объекту, как следствие - выше производительность

можно передать в объект класса функтор для финализации
Код

class Foo
{
  boost::function <void()> fn_;
  Foo(boost::function <void()> f) : fn_(f)
  {
  }
  ~Foo()
  {
    if (fn_ != 0)
      fn_();//<---finalize
  }
};

std::list<Foo*> foo_list;

.....
std::list<Foo*>::iterator i = foo_list.insert(foo_list.begin(), 0);

Foo *foo = new Foo(  boost::bind(&list<Foo>::erase, &foo_list/*this*/,  i/*что удалять*/)  );

*i = foo;

.....

delete *i;//вызовет foo_list.erase(i);

Автор: Alek86 29.5.2008, 11:58
Цитата(Lazin @  29.5.2008,  11:44 Найти цитируемый пост)
написать код - удаляющий элементы контейнера, но не изменяющий сам объект, 

поскольку это list, то ничего страшного не произойдет
если удаляешь какой-то элемент, то остальные трогать не надо (все итераторы остаются валидными) а единственный, который надо - это тот, который только что удалил smile


Цитата(Lazin @  29.5.2008,  11:44 Найти цитируемый пост)
во вторых такой объект не сможет использоваться без контейнера,

само собой
и потому я и говорил про спец класс - он в себе будет хранить подкласс-элемент
типа такого:

Код

#include <list>

template <typename ElemT>
class MyList {
public:
 // funcs
 // переопределить вставку, получение элемента и т.п.
private:
 // types
 template <typename T>
 struct MyElement {
  typedef T* Data;
  typedef std::list<MyElement<Data> > List;
  typedef typename List::iterator DataReference;
  Data m_data;
  DataReference m_ref;
 };
 // vars
 typename MyElement<ElemT>::List m_impl;
};

комментить лень было, но, надеюсь, суть ясна

Автор: Lazin 29.5.2008, 12:02
Цитата(Alek86 @  29.5.2008,  11:58 Найти цитируемый пост)
поскольку это list, то ничего страшного не произойдет
если удаляешь какой-то элемент, то остальные трогать не надо (все итераторы остаются валидными) а единственный, который надо - это тот, который только что удалил

я про этот случай и говорил

Автор: Alek86 29.5.2008, 12:10
Цитата(Lazin @  29.5.2008,  12:02 Найти цитируемый пост)
я про этот случай и говорил

так что же в нем плохого?

Добавлено через 1 минуту и 54 секунды
а, ну да
для использования этого механизма нужно-таки открыть MyList::MyElement
закрыть нужно итератор MyList::MyElement::m_ref

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)