crossplatform.ru

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

 
Ответить в данную темуНачать новую тему
> наступил на замечательные грабли
Алексей1153
  опции профиля:
сообщение 8.12.2012, 23:12
Сообщение #1


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

Группа: Участник
Сообщений: 2939
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

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




Репутация:   34  


из примера, думаю, понятно ))) Только у меня там хранились указатели, да не просто указатели, а на объекты, хранящиеся в QGraphicsScene. В итоге, сцена убивала объект в деструкторе, а я потом удалял из своего контейнера. Догадался о месте ошибки далеко не сразу ))))

typedef std::map<int,int> td_map;

td_map m;

m[0]=1;
m[1]=1;
m[2]=1;
m[3]=2;
m[4]=2;
m[5]=2;
m[6]=3;
m[7]=3;

//удаляем все двойки

//неправильно!
for(td_map::iterator it=m.begin();it!=m.end();it++)
{
    if(it->second==2)
    {
        m.erase(it++);
        if(it==m.end())break;
        //а в начале новой итерации пропустится один элемент!
    }
}

//ок
for(td_map::iterator it=m.begin();it!=m.end();/*it++*/)
{
    if(it->second==2)
    {
        m.erase(it++);
    }
    else
    {
        it++;
    }
}


Сообщение отредактировал Алексей1153 - 8.12.2012, 23:14
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Iron Bug
  опции профиля:
сообщение 9.12.2012, 9:55
Сообщение #2


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

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

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




Репутация:   12  


ну дык, зачем же два раза-то плюсовать итератор? он вообще не будет работать: итератор в цикле станет невалиден. удаление меняет связи в контейнере и после удаления элемента такой итератор бесполезно инкрементировать.
это подробно обсуждалось тут:
http://www.forum.crossplatform.ru/index.php?showtopic=8914
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 9.12.2012, 22:43
Сообщение #3


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

Группа: Участник
Сообщений: 2939
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

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




Репутация:   34  


Iron Bug, мне ооочень редко приходится в цикле править длину контейнера, а обычно после этого я выходил из цикла. Вот по инерции и оставил шапку цикла как было обычно

теперь я для себя запомнил - правишь длину контейнера, убирай "автоинкремент". Только вручную
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ssoft
  опции профиля:
сообщение 10.12.2012, 7:05
Сообщение #4


Участник
**

Группа: Участник
Сообщений: 130
Регистрация: 17.2.2010
Из: Москва
Пользователь №: 1470

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




Репутация:   3  


Тогда уж лучше так

//ок
for(td_map::iterator it=m.begin();it!=m.end();/*it++*/)
{
    if(it->second==2)
    {
        it = m.erase( it );
    }
    else
    {
        ++it;
    }
}


а еще лучше

inline
bool removeCondition ( const td_map::value_type & value ) { return value.second == 2; }

//....
void funct()
{
    std::remove_if( m.begin(); m.end(); removeCondition );
};

Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 10.12.2012, 9:37
Сообщение #5


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

Группа: Участник
Сообщений: 2939
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

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




Репутация:   34  


ssoft, префиксный инкремент у итераторов не люблю - мне просто напросто некрасиво :) Скажешь - производительность. Та там ерунда, а кроме того - оптимизатор всё равно сделает без создания копии, так как старое значение не используется

>> it = m.erase( it );
можно и так, в общем-то, даже более универсально будет )


предикаты хороши, но на их написание нужно отвлекаться, а тут проверка простейшая, цикл же пишется на автомате и быстро )

Сообщение отредактировал Алексей1153 - 10.12.2012, 9:40
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Iron Bug
  опции профиля:
сообщение 10.12.2012, 13:16
Сообщение #6


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

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

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




Репутация:   12  


Цитата(Алексей1153 @ 10.12.2012, 12:37) *
напросто некрасиво Скажешь - производительность.

Цитата(Алексей1153 @ 10.12.2012, 12:37) *
можно и так, в общем-то, даже более универсально будет )

внимание! ты сейчас делаешь грубую ошибку. ты не наступил на куда более страшные грабли, просто из-за "красоты текста". а вещь-то принципиальная! префиксный инкремент там недопустим. почитай тот топик, который я выше указала. до полного понимания.

Сообщение отредактировал Iron Bug - 10.12.2012, 13:18
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 10.12.2012, 13:39
Сообщение #7


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

Группа: Участник
Сообщений: 2939
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

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




Репутация:   34  


Iron Bug, да я всё понимаю, когда какой нужен :) Речь была именно про строку

Цитата(ssoft @ 10.12.2012, 10:05) *
 ++it;


то есть - голый инкремент

это некоторые с пеной у рта любят уверять, что

for(;;++i)
работает быстрее, чем

for(;;i++)

:)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Iron Bug
  опции профиля:
сообщение 10.12.2012, 16:09
Сообщение #8


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

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

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




Репутация:   12  


тут не просто инкремент, а инкремент итератора. процедура, зависящая от состояния контейнера. и дело именно в том, что после удаления элемента итератор становится невалиден. нельзя инкрементировать итератор, когда элемент, на который он ссылался, удалён.
и компилятор тут ни при чём. тут нет оптимизации на уровне компилятора, ибо это далеко не атомарная операция.

Сообщение отредактировал Iron Bug - 10.12.2012, 16:13
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 11.12.2012, 18:59
Сообщение #9


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

Группа: Участник
Сообщений: 2939
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

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




Репутация:   34  


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

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


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




RSS Текстовая версия Сейчас: 20.4.2024, 1:19