.end() и .push_back()

Тема в разделе "LANGS.C", создана пользователем _DEN_, 26 апр 2009.

  1. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    Сцена первая:
    Код (Text):
    1. std::vector<int> vec;
    2. vec.reserve(10);
    3. vec.push_back(1);
    4. vec.push_back(2);
    5. std::vector<int>::const_iterator vend = vec.end();
    6. vec.push_back(3);
    7. std::cout << *vend << std::endl; // Вывод '3'
    Сцена вторая:
    Код (Text):
    1. std::list<int> ls;
    2. ls.reserve(10);
    3. ls.push_back(1);
    4. ls.push_back(2);
    5. std::list<int>::const_iterator lend = ls.end();
    6. ls.push_back(3);
    7. std::cout << *lend << std::endl; // Ошибка, т.к. lend после вставки всеравно остался end-ом
    Отсюда вопрос: откуда именно вытекает подобное поведение сохраненного end-итератора? Это:
    1. Unspecified behavour?
    2. Implementation-defined behavior? Если да то для кого?
    3. Вытекает из iterator_category?

    Почему это происходит с точки зрения реализации я понимаю, это опустим. Интересует в чем состоят требования к поведению с точки зрения Стандарта и в чем они выражаются?
     
  2. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    _DEN_
    iterator::end() указывает не на последний элемент вектора, а за конец вектора
     
  3. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    для списка, iterator::end()==null


    все это для того чтобы обход контейнера итератором выглядел так
    for(; it != container.end() ;++it)
     
  4. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    GoldFinch

     
  5. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    _DEN_
    реализация полностью соответствует стандарту, возьми его и почитай
     
  6. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    GoldFinch

    Бугага. Во-первых, резве я говорил, что реализация не соответствует стандарту? Во-вторых, форум наверно для того и существует, чтобы облегчить поиск информации? Стандарт это 1000-страничный документ на английском языке. Как искать-то предлагаешь? Ctrl-F "Stored end iterator behavior"?
     
  7. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    _DEN_
    что значит Stored end iterator?
    это просто итератор указывающий на конец контейнера в данный момент времени
    если поменять конец контейнера, это уже не будет итератор указывающий на конец контейнера
    то что он const говорит только о том что ты не будешь менять состояние контейнера
     
  8. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    GoldFinch

    Для вектора - да. Для листа - нет. Мой вопрос в том и состоит, чтобы понять, чем диктуется и откуда вытекает это поведение.

    Это-то тут причем?

    PS. Меня _НЕ_ интересует реализация - я прекрасно понимаю как оно устроено и откуда берется такое поведение на примере конкретной платформы, модели памяти и компилятора. Не надо меня учить основам языка и его стандартной библиотеки - я знаю как примеряются итераторы, почему была выбрана концепция end-итераторов и какие она дает удобства, каким образом принято итерировать контейнеры, какие гарантии есть относительно времени жизни итераторов после модификации контейнера, и многое другое. Не надо предлагать смотреть сорцы stl или дизасмить exe-шники. Не нужно на все это тратить время.

    У меня есть конкретный вопрос: поведение сохраненного end-итератора после push_back зависит от типа контейнера. Чем с точки зрения Стандарта это поведение продиктовано?
     
  9. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    _DEN_
    Это вытекает из свойств контейнеров:
    end() возвращает итератор, который по Стандарту может НЕ быть разыменовываемым (dereferenceable).
    Поэтому *vend и *lend недопустимы.
     
  10. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    green

    Но ведь после .push_back() ситуация несколько меняется? По-твоему работающий *vend - implementation-defined behavior?
     
  11. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    green

    Кстати, мотивационный пример тут не в разыменовании итератора.

    Код (Text):
    1. template <class container>
    2. void foo(container& cnt)
    3. {
    4.     typename container::const_iterator beg = cnt.begin();
    5.     typename container::const_iterator end = cnt.end();
    6.    
    7.     // Вставка в контейнер.
    8.     // ...
    9.  
    10.     std::copy(beg, end std::ostream_iterator<typename container::value_type>(std::cout << "Было: "));
    11.  
    12.     std::copy(cnt.begin(), cnt.end(), std::ostream_iterator<typename container::value_type>(std::cout << "Стало: "));
    13. }
    Так что ничего противозаконного мы не делаем, но вопрос поведения сохраненного end-а остается.
     
  12. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    _DEN_
    Да. Стандарт оговаривает только случаи, когда операция на контейнером может invalidate итераторы этого контейнера.
    В частности, для вектора и листа гарантируется сохранение валидности всех итераторов при push_back.

    То, что невалидные итераторы могут случайно стать валидными - обычное дело: например, можно снести и повторно создать контейтер - если менеджер памяти решит расположить его по старому адресу, все итераторы, полученные от старого контейнера, останутся валидными. Но это уже чисто chance-defined behavior. :derisive:
     
  13. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    green

    Для вектора как раз таки не гарантируется. Векторные итераторы не поломаются только если не произойдет реаллокации памяти, выделенной под вектор. На 100% это можно гарантировать только воспользовавшись функцией .reserve();

    И все-таки, мотивационный пример. Разыменований не происходит, однако результат зависит от поведения сохраненного .end().
     
  14. RedLord

    RedLord Member

    Публикаций:
    0
    Регистрация:
    23 июн 2005
    Сообщения:
    183
    Адрес:
    Ukraine
    _DEN_
    это и есть ответ на вопрос.
    в случае с вектором - итератор мог остаться end, а мог начать указывать на валидное значение.
    и рассчитывать на такое поведение нельзя.
    в cлучае со списком - все нормально. итератор конца - всегда будет валиден и соответственно указываеть на end
     
  15. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    RedLord

    После push_back остаться end-ом в существующих реализациях он никак не может - либо следующее значение, либо итератор с bad pointer-ом внутри, но никак не end.


    Можно - reserve();
     
  16. RedLord

    RedLord Member

    Публикаций:
    0
    Регистрация:
    23 июн 2005
    Сообщения:
    183
    Адрес:
    Ukraine
    _DEN_
    я исходил из примера и каммента:
    поэтому reserve и
    не рассматривал ;)
     
  17. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    _DEN_
    Да, точно, для вектора Стандарт гарантирует валидность итераторов при отсутствии релокации (size() < capacity()).
    Дело в том, нет никакого специального end-итератора, который обязательно сохраняет свой end-status независимо от состояния контейнера.
     
  18. Velheart

    Velheart New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2008
    Сообщения:
    526
    есть два типа контейнеров: последовательные и ассоциативные, для последовательных(в частности вектор) при вставке-удалении все итераторы становятся невалидными, для ассоциативных(в частности лист) -- нет
     
  19. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Velheart
    Лист и вектор относятся к последовательным контейнерам.
    Для vector::insert Стандарт гарантирует валидность итераторов при условии size() + numItemsToInsert < capacity() (т.е. при отсутствии релокации). list::insert сохраняет итераторы всегда.
     
  20. Velheart

    Velheart New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2008
    Сообщения:
    526
    green
    упс, сорри, облажался, не проверил, т.к. казалось интуитивно понятным, что лист должен быть ассоциативным..