Проверьте, принадлежит ли итератор к списку - PullRequest
15 голосов
/ 10 июня 2011

Есть ли способ проверить, принадлежит ли данный итератор данному списку в C ++?

1 Ответ

18 голосов
/ 10 июня 2011

Очевидный, но неверный подход

Вы не можете просто выполнить итерацию по списку, сравнивая каждое значение итератора с вашим «кандидатом».

Стандарт C ++ 03 неясен в отношениидопустимость == применяется к итераторам из разных контейнеров (комментарий Манкарса по ссылкам ответа Наваза http://www.open -std.org / jtc1 / sc22 / wg21 / docs / paper / 2009 / n2948.html # 446 )некоторые компиляторы (например, режим отладки VC ++ 2005) предупреждают, если вы это делаете, но, несмотря на все это, он может действительно работать надежно в зависимости от вашего компилятора / библиотек - проверьте его документацию, если вам не нужна переносимость.

Стандарт C ++ 11 очень явный, вы не можете сравнивать итераторы с разными контейнерами :

§ 24.2.5 Область == для прямых итераторовэто итераторы по одной и той же базовой последовательности.

Итак, ответы на этот вопрос, основанные на operator==, сомнительны сейчас и недействительны в будущем.

Частодействительный подход

Что заu может сделать - выполнить итерацию по списку, сравнивая адрес элементов (т.е. &*i) с адресом объекта, на который указывает ваша другая итерация.

  • Комментарий Манкарса предупреждает, что это может не работать так, как предназначено для объектов, предоставляющих свои operator&.Вы можете обойти это, используя std::addressof или для C ++ 03 версию Boost

  • В комментарии Мартина упоминается, что вы должны принятьИтератор-кандидат, для которого вы тестируете членство в списке, безопасно разыменован, т. е. не равен итератору end() для контейнера, из которого он получен.Как отмечает Стив - это довольно разумное предварительное условие и никого не должно удивлять.

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

Реализация:

template <class IteratorA, class IteratorB, class IteratorC>
inline bool range_contains(IteratorA from, const IteratorB& end,
                           const IteratorC& candidate)
{
    while (from != end)
        if (&*from++ == &*candidate)
            return true;
    return false;
}

Примечания:

  • Это принимает стандартный подход библиотеки для принятия диапазона итераторапозиции для поиска.
  • Разрешается варьировать типы каждого итератора, поскольку существуют проблемы с переносимостью, например контейнеры, в которых begin() возвращает iterator, но end() возвращает const_iterator.
  • Итераторы, отличные от from, берутся по ссылке const, поскольку итераторы иногда могут быть нетривиальными объектами (т.е. слишком большимиGe, чтобы вписаться в реестр, относительно дорого, чтобы скопировать).from необходимо по значению, поскольку оно будет увеличиваться в диапазоне.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...