.end() и .push_back()

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

  1. _DEN_

    _DEN_ DEN

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

    Ну блин, list-то сохраняет)) И map сохраняет))
     
  2. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    _DEN_
    Но по Стандарту не обязан. :)
    container.end() возвращает обычный итератор. Разве что не разыменовываемый на момент получения.
    Его "конечность" определяется результатом сравнения с текущим значением container.end() и ничем другим.
    А end() не обязан возвращать всегда один и тот же итератор.
     
  3. _DEN_

    _DEN_ DEN

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

    Тогда это противоречит утверждению о том, что последовательные итераторы остаются живыми после операции вставки/удаления :derisive:
     
  4. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    _DEN_
    Впрочем, для вектора можно сделать реализацию итератора, при которой end() всегда будет возвращать один и тот же итератор.
    Например:
    class vector::iterator
    {
    vector *pMyVector_;
    size_t elementIndex_; // -1 для end-итератора

    // ...
    };
     
  5. _DEN_

    _DEN_ DEN

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

    Нельзя :) Точнее - поломается куча оптимизаций и вектор по многим параметрам скатится до листа. Придется ставить костыли в операторе сравнения итераторов, std::distanse и std::vector::at получат линейную сложность вместо константной, и еще много всего неприятного.
     
  6. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    _DEN_
    Почему? Растолкуй в чём противоречие.
     
  7. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    _DEN_
    Вот-вот. Нельзя требовать от всех контейнеров абсолютно одинакового поведения - каждый заточен под что-то своё.
     
  8. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    green: Для листа гарантируется сохранение валидности всех итераторов при push_back.
    green: Дело в том, нет никакого специального end-итератора, который обязательно сохраняет свой end-status независимо от состояния контейнера.

    Вот в этом противоречие.


    green

    Так я и не требую :) Мой изначальный вопрос, который кстати так и остался открытым - чем диктуется поведение сохраненного end-а после операции вставки, при условии что итератор остался валиден? ))) Мы тут уже обсудили все, кроме самого вопроса)))
     
  9. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    _DEN_
    Противоречия нет. Для list::push_back (и, с оговорками, vector::push_back) гарантируется сохранение валидности. Т.е. если итератор до push_back был валидным до push_back, то таковым и останется.
    А сохранение невалидности (т.е. что невалидный итератор таковым и останется) не гарантируется, конечно. :)
    Или я не понял?

    Т.е. почему (с точки зрения Стандарта) у вектора после вставки end_before_insert != vector.end(), а у листа == ?

    Из-за того, что Стандарт не требует равенства vector.end() до и после вставки, реализация вектора в целях эффективности сделана с изменяемым end().
    Возможны стандарт-совместимые реализации вектора с неизменным end(), но менее эффективные.

    Чем не ответ? :derisive:
     
  10. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    _DEN_
    По-моему ты слишком многого хочешь от С++. У меня тоже нет полноценного стандарта, только какой-то ошлёпок который вряд ли на него может претендовать, но там нет ни слова о том о чём ты пишешь. По-моему стандарт определяет только внешний интерфейс поведения. Например те же требования к итераторам. По-моему элементы вектора не обязательно должны располагать в памяти последовательно, а списка нет. Если их внешний интерфейс удовлетворяет требованиям, то почему бы и нет. А всё то, что опирается на конкретную реализацию, по-определению не корректно. Другой вопрос, что часто конкретная реализация выглядит почти как стандартная(например не POD структуры которые выглядят как POD). Думаю этот случай примерно из той же самой оперы.
     
  11. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    green
    Просто в данной реализации так вышло, что end() указатель на следующий за валидным элементом массива, что является разумным и эффективным. Но никто не запрещает сделать иначе.
     
  12. _DEN_

    _DEN_ DEN

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

    end-итератор не является невалидным итератором :) end-итератор можно использовать в диапазонных алгоритмах, но нельзя разыменовывать. Невалидный итератор нельзя разыменовывать и нельзя использовать в алгоритмах. У end-итератора особый статус.


    Ну вот об этом-то и речь. Можешь ткнуть в стандарте где именно сказано, что "вот тут равенство требуется, а вот тут - не требуется"?


    Booster

    На счет C++98 не уверен, но начиная с C++2003 точно стандарт требует непрерывности буффера вектора.

    Стандарт - это 1000 страниц текста мелким шрифтом. Он определяет очень многие вещи в самых мельчайших подробностях.
     
  13. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    _DEN_

    У меня около 800 не очень мелкого, и по-моему стандарт многие вещи даже в новых версиях оставляет на усмотрение.

    Если так то звиняйте, у меня кусок от 98. ^) Интересно с чего это вдруг решили залезть внутрь реализации? И он требует, чтобы итераторы располагались строго последовательно тоже?
     
  14. _DEN_

    _DEN_ DEN

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

    Ну если стандарт говорит о какой-то конкретной модели памяти (или семействе моделей), то требование в общем-то вполне себе ничего. Кстати та же самая непрерывность гарантируется у std::basic_string::c_str(), std::basic_string::data и, если не ошибаюсь, у любого &*std::basic_string::dntknw:const_)iterator.

    Не совсем понял, что значит "итераторы располагаются последовательно"?. std::vector::dntknw:const_)iterator имеет оператор "меньше". Между элементами дырок (выравнивания) нет.
     
  15. green

    green New Member

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

    AFAIK, Стандарт не накладывает никаких ограничений на значение end() кроме вот этого:
    Значит реализации позволяется делать end() изменяемым.
     
  16. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    _DEN_
    Этому могу дать объяснение, только желанием работать с вектором как и с обычным массивом. Но тогда это накладывает ограничение и на сам этот массив, необходимо чтобы он точно соответствовал своей обычной реализации. Но всё-таки не понятно зачем это было сделано, вектор нисколько не уступает по эффективности обычному массиву.

    Не корректно выразился. Имел ввиду последовательность соответствующих элементов данных.
     
  17. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    Booster
    Ты про это?

    ЗЫ: _DEN_ - приношу извинения, что тоже влез с обсуждением реализации, а не стандарта, но очень любопытно узнать на чём основано такое интересное замечание Booster.
     
  18. _DEN_

    _DEN_ DEN

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

    Вектор действительно нисколько не уступает по эффективности обычному массиву. Единственное что я не понял - это к чему это было сказано :)
     
  19. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Booster
    Полагаю, для того, чтобы позволить делать нечто вроде:
    Код (Text):
    1. memcpy(pRawBuffer, &v[0], v.size() * sizeof(vector::value_type));
     
  20. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    _DEN_
    Код (Text):
    1.     int testArray[100];
    2.     for (int i = 0; i<100; i++) testArray[i] = i;
    3.     vector <int> v1( 100 );
    4.     for (int i = 0; i<100; i++) v1[i] = i;
    компилится MSVC 9 /RELEASE /O2 в:
    Код (Text):
    1.     testArray[i] = i;
    2. 00401021  mov         dword ptr [esp+eax*4+28h],eax
    3. ...
    4.     v1[i] = i;
    5. 00401060  mov         edx,dword ptr [esp+1Ch]
    6. 00401064  sub         edx,dword ptr [esp+18h]
    7. 00401068  sar         edx,2
    8. 0040106B  cmp         esi,edx
    9. 0040106D  jb          wWinMain+71h (401071h)
    10. 0040106F  call        edi  
    11. 00401071  mov         eax,dword ptr [esp+18h]
    12. 00401075  mov         dword ptr [eax+esi*4],esi
    Конечно соглашусь, что накладных расходов относительно немного, но до "не уступает по эффективности" несколько не дотягивает, тем более что практическая ситуация когда дополнительная проверка каждого элемента точно не нужна, а скорость критична не такая уж и редкость.