Хранение итераторов внутри контейнеров - PullRequest
4 голосов
/ 16 июля 2009

Я создаю DLL, которую будет использовать другое приложение. Я хочу сохранить текущее состояние некоторых данных глобально в памяти DLL перед возвратом из вызова функции, чтобы я мог повторно использовать состояние при следующем вызове функции.

Для этого мне нужно сохранить несколько итераторов. Я использую std :: stack для хранения всех других данных, но я не был уверен, смогу ли я сделать это и с итераторами.

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

Я знаю, что использование вектора для хранения моих данных вместо списка позволило бы мне сохранять индекс и использовать его очень легко, но, к сожалению, мне приходится использовать только std :: list.

Ответы [ 7 ]

6 голосов
/ 16 июля 2009

Итераторы для списка становятся недействительными, только если список уничтожен или «указанный» элемент удален из списка.

5 голосов
/ 16 июля 2009

Да, все будет хорошо.

Поскольку многие другие ответы продолжают об этом как об особом качестве итераторов списка, я должен отметить, что он будет работать с любыми итераторами, включая векторные. Тот факт, что векторные итераторы становятся недействительными при изменении вектора, вряд ли имеет отношение к вопросу о том, разрешено ли хранить итераторы в другом контейнере - это равно . Конечно, итератор может быть признан недействительным, если вы сделаете все, что делает его недействительным, но это не имеет никакого отношения к тому, хранится ли итератор в стеке (или в любой другой структуре данных).

4 голосов
/ 16 июля 2009

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

То есть, если вы делаете:

std::list<int>::iterator it = myList.begin ();
std::list<int> c = myList;

c.insert (it, ...); // Error

Как отмечали другие: Конечно, вы также не должны делать недействительным итератор, удаляя указанный элемент.

2 голосов
/ 16 июля 2009

Это может быть оффтоп, но просто подсказка ...

Имейте в виду, что ваша функция (и) / структура данных, вероятно, будут небезопасными для операций чтения. Существует своего рода базовая безопасность потоков, где операции чтения не требуют синхронизации. Если вы собираетесь хранить информацию о том, как много читатель прочитал из вашей структуры, это сделает весь концептуальный поток небезопасным и немного неестественным для использования. Потому что никто не предполагает чтение для операции с полным состоянием.

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

Я бы предложил сделать две перегруженные функции. Оба не имеют состояния, но один из них должен принять итератор подсказок, с которого начинать следующее чтение / поиск / поиск и т. Д. Это, например, как реализован Allocator в STL. Вы можете передать в распределитель указатель подсказки (по умолчанию 0), чтобы он быстрее находил новый фрагмент памяти.

С уважением,
Ованес

1 голос
/ 16 июля 2009

Хранение итератора для списка должно быть в порядке. Он не станет недействительным, если вы не удалите тот же элемент из списка, для которого вы сохранили итератор. Следующая цитата с сайта SGI :

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

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

0 голосов
/ 16 июля 2009

Да. Список - это путь. Мой ответ на аналогичный вопрос вы можете найти здесь: Что такое время жизни и срок действия итераторов C ++:

0 голосов
/ 16 июля 2009

То же правило применяется к итератору, хранящемуся в локальной переменной, как и в более долгоживущей структуре данных: оно будет оставаться действительным, пока позволяет контейнер.

Для списка это означает: пока узел, на который он указывает, не удален, итератор остается действительным. Очевидно, что узел удаляется при разрушении списка ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...