crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

3 страниц V  < 1 2 3  
Ответить в данную темуНачать новую тему
> Удаление элементов из списка std::list в цикле
Влад
  опции профиля:
сообщение 19.10.2012, 12:10
Сообщение #21


Участник
**

Группа: Участник
Сообщений: 146
Регистрация: 20.3.2009
Из: Санкт-Петербург
Пользователь №: 627

Спасибо сказали: 46 раз(а)




Репутация:   8  


В общем, в результате изучения Стандарта (D_K спасибо за ссылку на 24.4.1) у меня сложилось устойчивое впечатление, что "падающий" код - это следствие косяков конкретных реализаций. Стандарт устанавливает только требования к интерфейсу reverse_iterator, но ничего не говорит о его внутреннем устройстве; это абсолютно нормально. Равным образом, в Стандарте нет требования (requirement) о том, что reverse_iterator обязательно должен содержать iterator, указывающий на предыдущий элемент, - тот самый, который становится невалидным в нашем коде, и основывать свою работу на нем. Таким образом, это остается на усмотрение разработчиков реализации....

К сожалению, в большинстве случаев мы сильно ограничены в выборе реализаций STL.
Теоретически, код из поста #10 не противоречит Стандарту и абсолютно валиден (и это тот же самый совет Мейерса #28, только записанный немного подробнее). Однако в конкретных реализациях мы видим, что он не работает. Увы.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
D_K
  опции профиля:
сообщение 19.10.2012, 15:06
Сообщение #22


Студент
*

Группа: Участник
Сообщений: 20
Регистрация: 20.5.2009
Пользователь №: 761

Спасибо сказали: 3 раз(а)




Репутация:   1  


Влад, а как же
Цитата(24.4.1.1)
namespace std {
    template <class Iterator>
    class reverse_iterator : public
        iterator<typename iterator_traits<Iterator>::iterator_category,
                     typename iterator_traits<Iterator>::value_type,
                     typename iterator_traits<Iterator>::difference_type,
                     typename iterator_traits<Iterator>::pointer,
                     typename iterator_traits<Iterator>::reference> {
    protected:
        Iterator current; // <---
...

Ну и дальше все операции через current расписаны...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Влад
  опции профиля:
сообщение 19.10.2012, 15:35
Сообщение #23


Участник
**

Группа: Участник
Сообщений: 146
Регистрация: 20.3.2009
Из: Санкт-Петербург
Пользователь №: 627

Спасибо сказали: 46 раз(а)




Репутация:   8  


Тут бы я не согласился. Вот этот самый current - исключительно деталь внутренней реализации реверсивного итератора. И, в то же время, Стандарт иллюстрирует effects через current, но не дает никаких указаний о содержимом current после операций типа erase/insert и о моментах его обновления. В то же время, в Ст.23.2.2.3 (напоминает "Матф. 18:13", не правда ли? :-) ) явно указывает:
Effects: Invalidates only the iterators and references to the erased elements.
Учтем, что в этот момент reverse_iterator не указывает на erased element, а о его внутреннем устройстве (в том числе, о protected членах) я, как "внешний" пользователь, вообще ничего знать не обязан. :-) А нежелательные эффекты возникают из-за излишне прямолинейного копирования иллюстративного кода в Стандарте - в программный код. Т.е., я имею в виду, что код должен следовать требованиям Стандарта по принципу "включая, но не ограничиваясь". А вот это, видимо, выполняется не во всех реализациях.

Дискуссия по этому вопросу и возражения приветствуются!
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
D_K
  опции профиля:
сообщение 19.10.2012, 17:10
Сообщение #24


Студент
*

Группа: Участник
Сообщений: 20
Регистрация: 20.5.2009
Пользователь №: 761

Спасибо сказали: 3 раз(а)




Репутация:   1  


ИМХО. Стандарт, в первую очередь, предназначен для реализаций языка.
И по-моему, вот из этого:
Цитата
explicit reverse_iterator(Iterator x);

Effects: Initializes current with x.

...

Iterator base() const;

Returns: current

...

reference operator*() const;

Effects:
Iterator tmp = current;
return *--tmp;

...

pointer operator->() const;

Effects:
return &(operator*());

...

reverse_iterator& operator++();

Effects: --current;
Returns: *this

...

reverse_iterator operator--(int);

Effects:
reverse_iterator tmp = *this;
--current;
return tmp;

следует, что итератор станет невалидным...

Кроме того, Iteratir current - это protected-член. Соответственно, это часть интерфейса наследования.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Iron Bug
  опции профиля:
сообщение 19.10.2012, 19:56
Сообщение #25


Профессионал
*****

Группа: Модератор
Сообщений: 1611
Регистрация: 6.2.2009
Из: Yekaterinburg
Пользователь №: 533

Спасибо сказали: 219 раз(а)




Репутация:   12  


если вкратце, то erase превращает итератор в так называемое singular value. можно представить его как аналог NULL для указателей. это значение, не принадлежащее ни одному контейнеру. поэтому после erase итератор становится невалиден и постфиксная операция iter++ будет невалидна. а вот если взять префиксный плюс (++iter) прямо внутри вызова erase, то всё будет ok, потому что сначала итератор изменится, а его "старое" значение будет скопировано, копия будет использована в erase и перейдёт в singular value.

Сообщение отредактировал Iron Bug - 19.10.2012, 19:58
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
D_K
  опции профиля:
сообщение 20.10.2012, 15:54
Сообщение #26


Студент
*

Группа: Участник
Сообщений: 20
Регистрация: 20.5.2009
Пользователь №: 761

Спасибо сказали: 3 раз(а)




Репутация:   1  


Iron Bug, так не об этом речь. reverse_iterator'ы обсуждаем.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Iron Bug
  опции профиля:
сообщение 20.10.2012, 19:02
Сообщение #27


Профессионал
*****

Группа: Модератор
Сообщений: 1611
Регистрация: 6.2.2009
Из: Yekaterinburg
Пользователь №: 533

Спасибо сказали: 219 раз(а)




Репутация:   12  


Цитата(D_K @ 20.10.2012, 18:54) *
Iron Bug, так не об этом речь. reverse_iterator'ы обсуждаем.

именно об этом. реверс-итератор ничем принципиально не отличается от обычного итератора и у него при вызове erase точно также будут работать префиксные плюсы и не будут работать постфиксные.

Сообщение отредактировал Iron Bug - 20.10.2012, 19:03
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
D_K
  опции профиля:
сообщение 21.10.2012, 23:41
Сообщение #28


Студент
*

Группа: Участник
Сообщений: 20
Регистрация: 20.5.2009
Пользователь №: 761

Спасибо сказали: 3 раз(а)




Репутация:   1  


Iron Bug, как вы собираетесь делать erase с reverse_iterator'ом? Это возможно только через метод base(), возвращающий обычный итератор.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Iron Bug
  опции профиля:
сообщение 22.10.2012, 7:15
Сообщение #29


Профессионал
*****

Группа: Модератор
Сообщений: 1611
Регистрация: 6.2.2009
Из: Yekaterinburg
Пользователь №: 533

Спасибо сказали: 219 раз(а)




Репутация:   12  


Цитата(D_K @ 22.10.2012, 2:41) *
Iron Bug, как вы собираетесь делать erase с reverse_iterator'ом? Это возможно только через метод base(), возвращающий обычный итератор.

и чем же он плох? просто erase сам по себе не принимает обратный итератор. но сам итератор от этого ничуть не страдает.

вот обычный метод, который работает, удаляя элементы в обратном порядке.
#include <iostream>
#include <list>

using namespace std;

int main(int argc, char* argv[])
{
    list<int> data;
    for(int i=0; i<1000; i++)
    {
        data.push_back(i);
    }
    list<int>::reverse_iterator iter;
    iter = data.rbegin();
    do
    {
        data.erase(--iter.base());
    }
    while(iter != data.rend());
    cout << data.size() << endl;
    return 0;
}
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
D_K
  опции профиля:
сообщение 22.10.2012, 11:12
Сообщение #30


Студент
*

Группа: Участник
Сообщений: 20
Регистрация: 20.5.2009
Пользователь №: 761

Спасибо сказали: 3 раз(а)




Репутация:   1  


Неясно, к чему это.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

3 страниц V  < 1 2 3
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 29.3.2024, 8:14