У меня есть std :: list в программе на C++, которая содержит объекты класса A. Допустим, у меня в нем 10 объектов. У меня есть ссылка на 6-й объект, который хранится в другой структуре данных ref_6. Допустим, мне нужно удалить 8-й элемент из моего списка. Чтобы сделать это, я бы использовал pop_front 8 раз и сохранил 8 объектов в векторе и использовал push_front 7 раз, чтобы вставить первые 7 элементов в список, так что теперь в моем результирующем списке будет 9 элементов. Теперь, когда я пытаюсь получить доступ к объекту, хранящемуся в ref_6, который был 6-м элементом, я не могу это сделать. В этой ссылке есть некоторая ценность мусора. Я предполагаю, что когда я делаю поп и нажатие, меняется место памяти того же объекта. Как мне с этим справиться?Проблемы с контейнерами C++
ответ
Почему бы вам не стереть тактику? 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
И никакие другие итераторы не аннулируются. (Действительно, удаление элемента аннулирует любые ссылки на него.)
* Вы, вероятно, не даже с использованием списка. Списки хороши, когда дело доходит до обучения структурам данных, но они довольно ужасны.
Список хранит свои элементы в прерывистых кусках памяти, которые освобождаются, когда элемент удаляется из списка. Таким образом, ссылка (которая реализуется просто как указатель) указывает на элемент, память которого уже освобождена.
Легче способ удалить данный элемент из списка, чтобы получить итератор, указывающий на него и метод использования
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);
Что-то пахнет тусклый здесь ... Вы хранящий 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
, проблема будет такой же.
вы говорите, что я держу объект типа T по значению, но в stl_list у push_front есть этот прототип void push_front (const value_type & __x). Так что это не эта ссылка, это то же самое, что и значение. Кроме того, в другом месте, когда я сказал, что я держу ссылку, я фактически использовал указатели и, по моему мнению, вызывал проблему. Поэтому вы говорите, что если бы я использовал список shared_ptr, то я мог бы удалить и добавить элементы, и мои ссылки на эти элементы будут работать нормально. Сохраняется ли это, если я изменяю порядок элементов в списке, например, используйте pop_front для получения элемента, а затем push_back? – cyrux
Будет ли мой shared_ptr в этом случае работать правильно? – cyrux
Я имею в виду ваш ответ. К сожалению, я не получил счет вещь прямо ... Пожалуйста, обратите внимание на следующее:
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> >
!
- 1. проблемы с ограничениями с контейнерами
- 2. GHUnit с контейнерами какао
- 3. Корректность ошибок, вызывающая проблемы с контейнерами для указателей?
- 4. Выход с C# на C++, имеющий дело с контейнерами
- 5. Bluemix - проблемы с контейнерами IBM для Юга США?
- 6. Rackspace OpenCloud File Проблемы с вложенными контейнерами PHP API
- 7. Сопоставление между контейнерами stl C++ и C#
- 8. Зал с контейнерами Windows
- 9. Публикация исходного кода в блогере с ошибками с контейнерами C#
- 10. реализация признаков с stl-контейнерами
- 11. Директива с двумя контейнерами шаблон
- 12. TypeScript борется с контейнерами Redux
- 13. Как избежать утечек памяти, с C++ с контейнерами STL?
- 14. Итератор для прыжков между контейнерами C++
- 15. функция перерисовки с g контейнерами
- 16. Сервисная ткань с оконными контейнерами
- 17. Пребывание с контейнерами DI/IoC
- 18. CorePlot с контейнерами какао 0.38.2
- 19. комплекс flexbox с прокручиваемыми контейнерами
- 20. Эмблема вложенной маршрутизации с контейнерами
- 21. разница между контейнерами
- 22. Сортировка элементов с пользовательскими динамическими контейнерами
- 23. Использование RAII с потоками C++ и STL-контейнерами?
- 24. Когда имеет смысл использовать unique_ptr с контейнерами STL? (C++ 11)
- 25. Как обращаться с различными контейнерами C++ в общем?
- 26. kubectl exec в контейнер с несколькими контейнерами
- 27. (Re) Использование STD :: алгоритмы с нестандартными контейнерами
- 28. log4j столкновение с несколькими контейнерами ejb
- 29. MATLAB: Путаное поведение с контейнерами. Карта
- 30. OpenMP Nested For Loop с контейнерами STL
Таким образом, размер списка (начало памяти и расположение в конце памяти) остается таким, как есть, только один элемент удаляется/аннулируется. не так ли? – cyrux
Мне любопытно ваши комментарии к использованию списка в реальной жизни ---- Именно в STL по его причинам, как вы сказали: вставьте или удалите любой элемент в постоянное время –
@cyrux: Да, связанный список удалит этот элемент только, остальные действительны. @Dbger: стандартная библиотека включает его, потому что это такая общая структура данных и потому что у нее есть свои возможности. Но этого мало; ваша основная операция будет в основном повторяться через контейнер и часто удалять элементы и часто * делать это *. Ужасная кеш-согласованность, которую он имеет наряду с линейным временем доступа, на практике делает ее очень медленной; даже если вы удаляете что-то из среднего полу-часто, 'vector' /' deque' будет работать лучше из-за локальности. – GManNickG