2010-09-05 2 views
1

У меня есть std :: list в программе на C++, которая содержит объекты класса A. Допустим, у меня в нем 10 объектов. У меня есть ссылка на 6-й объект, который хранится в другой структуре данных ref_6. Допустим, мне нужно удалить 8-й элемент из моего списка. Чтобы сделать это, я бы использовал pop_front 8 раз и сохранил 8 объектов в векторе и использовал push_front 7 раз, чтобы вставить первые 7 элементов в список, так что теперь в моем результирующем списке будет 9 элементов. Теперь, когда я пытаюсь получить доступ к объекту, хранящемуся в ref_6, который был 6-м элементом, я не могу это сделать. В этой ссылке есть некоторая ценность мусора. Я предполагаю, что когда я делаю поп и нажатие, меняется место памяти того же объекта. Как мне с этим справиться?Проблемы с контейнерами C++

ответ

2

Почему бы вам не стереть тактику? D: Это не стек. Вся точка (и только point *) списка состоит в том, что вы можете удалить любой элемент в постоянное время. (Хотя найти его линейна.)

Просто сделай это:

typedef std::list<T> list_type; 

list_type mylist; // populate it 

list_type::iterator iter = mylist.begin(); 
std::advance(iter, 8); // move to 8th item 

mylist.erase(iter); // erase it 

И никакие другие итераторы не аннулируются. (Действительно, удаление элемента аннулирует любые ссылки на него.)


* Вы, вероятно, не даже с использованием списка. Списки хороши, когда дело доходит до обучения структурам данных, но они довольно ужасны.

+0

Таким образом, размер списка (начало памяти и расположение в конце памяти) остается таким, как есть, только один элемент удаляется/аннулируется. не так ли? – cyrux

+1

Мне любопытно ваши комментарии к использованию списка в реальной жизни ---- Именно в STL по его причинам, как вы сказали: вставьте или удалите любой элемент в постоянное время –

+1

@cyrux: Да, связанный список удалит этот элемент только, остальные действительны. @Dbger: стандартная библиотека включает его, потому что это такая общая структура данных и потому что у нее есть свои возможности. Но этого мало; ваша основная операция будет в основном повторяться через контейнер и часто удалять элементы и часто * делать это *. Ужасная кеш-согласованность, которую он имеет наряду с линейным временем доступа, на практике делает ее очень медленной; даже если вы удаляете что-то из среднего полу-часто, 'vector' /' deque' будет работать лучше из-за локальности. – GManNickG

0

Список хранит свои элементы в прерывистых кусках памяти, которые освобождаются, когда элемент удаляется из списка. Таким образом, ссылка (которая реализуется просто как указатель) указывает на элемент, память которого уже освобождена.

Легче способ удалить данный элемент из списка, чтобы получить итератор, указывающий на него и метод использования

std::list::iterator = /*somehow get the iterator to the 8th element*/
yourList.erase(8th_element_iterator);

Первый шаг (получение итератор на 8-й элемент) может быть сделано для пример, получая итератор begininning списка и продвижения его 7 позиций вперед:

std::list::iterator first_iter = yourList.begin();
std::list::iterator 8th_iter = std::advance(first_iter, 7);

0

Что-то пахнет тусклый здесь ... Вы хранящий O bject типа T по значению std::list<T>. Вы сохраняете ссылки на эти объекты в других местах. Это верно? Если да, я вижу несколько проблем ... Многие манипуляции списками могут привести к аннулированию хранимых ссылок, поскольку std::list<T> гарантирует только последовательный порядок значений элементов типа T. Если вы хотите сохранить ссылки на эти элементы в нескольких местах, используйте std::tr1::shared_ptr<T> и std::list<std::shared_ptr<T> >. Затем вы можете безопасно удалить или добавить (даже переместить) элементы в свой список, а ссылки, хранящиеся в других местах, остаются в силе. Опасайтесь хранения std::list<T>iterators, проблема будет такой же.

+0

вы говорите, что я держу объект типа T по значению, но в stl_list у push_front есть этот прототип void push_front (const value_type & __x). Так что это не эта ссылка, это то же самое, что и значение. Кроме того, в другом месте, когда я сказал, что я держу ссылку, я фактически использовал указатели и, по моему мнению, вызывал проблему. Поэтому вы говорите, что если бы я использовал список shared_ptr, то я мог бы удалить и добавить элементы, и мои ссылки на эти элементы будут работать нормально. Сохраняется ли это, если я изменяю порядок элементов в списке, например, используйте pop_front для получения элемента, а затем push_back? – cyrux

+0

Будет ли мой shared_ptr в этом случае работать правильно? – cyrux

0

Я имею в виду ваш ответ. К сожалению, я не получил счет вещь прямо ... Пожалуйста, обратите внимание на следующее:

std::list<A> tList; 
A tA; 

tList.push_back(tA); 
assert(&tA == &tList.back()); // boom! 

A *tAPtr = &tList.front(); 

tList.erase(tList.front()); 
// try to access tAPtr: 
tAPtr->Foo(); // boom! (probably) 

Дело в том, что экземпляры A сохраняются по значению (= скопировано), так что вы делаете это по своей сути небезопасный. Используйте вместо этого std::list<std::tr1::shared_ptr<A> >!

Смежные вопросы