Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: STL. Проблема с erase()  (Прочитано 20735 раз)
0 Пользователей и 1 Гость смотрят эту тему.
bebabo
Помогающий

ru
Offline Offline

WWW
« : 15-10-2007 16:22 » 

Столкнулся со странной проблемой. Есть класс, в нем static vector и static функция, которая работает с этим вектором, проверяя каждый объект на соответствие некому условию и если true - вырезает этот объект из вектора.

Код:
vector<Transition>::iterator t = Transition::trans.begin();
 
while(t != Transition::trans.end()){
    if(CheckShapeType((*t).GetFromShape(), sh)){
      trans.erase(t++);
    }
}

Результат - все те объекты, которые должны быть удалены - удаляются за исключением одного. Он полностью соответствует условия удаления, но не вырезается. Точнее, вырезается, если запустить цикл повторно.
Пробовал заменить вектор на список - еще хуже - уходит в бесконечный цикл.
Что здесь может быть не так?
Записан

Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #1 : 15-10-2007 16:44 » 

Цитата
Есть класс, в нем static vector и static функция

в студию класс, в нем static vector и static функцию Улыбаюсь
Записан

bebabo
Помогающий

ru
Offline Offline

WWW
« Ответ #2 : 15-10-2007 16:51 » new

class Transition : public Shape{
protected:
   string from_shape;
   string to_shape;
   string to_shape_text;
   string trigger;
   string body;
   string else_part;
public:
   static vector <Transition>   trans;
public:
   Transition(std::string& _name, CVisioShape& shape);
   string GetFromShape();
   string GetToShape();
   string GetTrigger();
   string GetBody();
   static void ClearTransitions();
private:
   void SetBody();
   bool SetTrigger();
};

код статичной функции в предыдущем посте
функция для проверки условия удаления
bool CheckShapeType(string& str, string& shape_type){
   std::string::size_type i = str.find(shape_type);
   return (i != std::string::npos) ? true : false;
}
« Последнее редактирование: 15-10-2007 16:53 от bebabo » Записан

Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #3 : 15-10-2007 17:08 » 

проведи эксперимент:
Код:
bool CheckShapeType(string& str, string& shape_type)
{
   return true;
}

всё ли удалится или тоже один элемент останется ?
Записан

bebabo
Помогающий

ru
Offline Offline

WWW
« Ответ #4 : 15-10-2007 17:23 » 

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

RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #5 : 15-10-2007 17:29 » 

bebabo, у меня нет уверенности, что постфиксный ++ работает корректно. Я бы сделал цикл на for - и нагляднее и надежнее.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
bebabo
Помогающий

ru
Offline Offline

WWW
« Ответ #6 : 15-10-2007 17:30 » 

RXL, пробовал. результат тот же
Записан

RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #7 : 15-10-2007 17:47 » 

Кстати - "return (i != std::string::npos) ? true : false;" - масло маслянное: оператор неравенства уже возвращает логическое значение.

Проверь:
Код: (C++)
for (vector<Transition>::iterator t = trans.begin(); t != trans.end(); t++)
        if (CheckShapeType(t->GetFromShape(), sh))
                trans.erase(t++);

GetFromShape() - я бы и тут проверил.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
bebabo
Помогающий

ru
Offline Offline

WWW
« Ответ #8 : 15-10-2007 17:59 » 

Кстати - "return (i != std::string::npos) ? true : false;" - масло маслянное: оператор неравенства уже возвращает логическое значение.
кстати, да)
GetFromShape - просто возвращает стринг from_shape
проверил. один так и не удалился
Записан

Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #9 : 15-10-2007 18:06 » 

bebabo,
а что за жестокая заморочка тут
Код:
std::string::size_type i = str.find(shape_type);
   return (i != std::string::npos) ? true : false;
, не проще ли
Код:
while(...)
{
    if((*t).GetFromShape() == sh)
    {
      ...
    }
}
?

или нету там оператора сравнения ?
Записан

bebabo
Помогающий

ru
Offline Offline

WWW
« Ответ #10 : 15-10-2007 18:20 » 

Алексей1153++, насчет заморочки -
функция CheckShapeType принимает два строковых аргумента from_shape и sh и далее определяет есть ли в from_shape вхождения sh. например, from_shape = "transition.12" или "transition.5", а sh = "transition". в данном случае будет true 
Записан

Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #11 : 15-10-2007 18:31 » 

странно, а что за циферка на конце ?
Записан

bebabo
Помогающий

ru
Offline Offline

WWW
« Ответ #12 : 15-10-2007 18:49 » 

Алексей1153++, циферка... как бы это объяснить ) циферка - это что-то вроде порядкового номера, так в visio (пишу плагин для него) именуются фигуры. например, если нарисовать условие перехода (transition), то эта фигура будет названа transition, следующая transition.1, ну и т.д.
Записан

RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #13 : 15-10-2007 19:00 » 

bebabo, в общем, поставь точку прерывания в CheckShapeType и посмотри, что там в параметрах происходит.

Кстати, я бы объявил так:
Код: (C++)
bool CheckShapeType(const string& str, const string& shape_type);
Ты же их не изменяешь в функции, а оптимизатору в помощь и вообще надежнее.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #14 : 15-10-2007 19:08 » 

Для меня пока ясно лишь одно. Если один элемент остаётся, то условие, как минимум, один раз НЕ выполняется.

bebabo, попробуй, чтобы исключить подозрения на erase, убрать проверку условия и просто удалить все элементы.

зы Согласен, с мнением, что код очено запутано написан. Это уменьшает место, но резко снижает читабельность и понимание.

Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #15 : 15-10-2007 19:27 » 

Джон, уже была похожая проверка:
https://forum.shelek.ru/index.php/topic,13224.msg158983.html#msg158983

Явно что-то в find или параметрах...
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
bebabo
Помогающий

ru
Offline Offline

WWW
« Ответ #16 : 16-10-2007 18:15 » 

бился весь день и только что обнаружил идиотскую ошибку в первоначальном варианте цикла

while(t != Transition::trans.end()){
    if(CheckShapeType((*t).GetFromShape(), sh)){
      trans.erase(t++);
    }
}

инкремент t происходит только когда CheckShapeType возвращает true. исправил, запустил все получилось как надо. то что я принимал в случае со списком за бесконечный цикл было просто зависанием цикла на случае false. но почему этот цикл не зависает в случае с вектором - загадка. и почему не срабатывает вариант с for(;Ага - тоже не понимаю
Записан

RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #17 : 17-10-2007 05:18 » 

Думаю, что с for тоже срабатывает, но там тоже притаилать ошибка.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #18 : 17-10-2007 05:21 » 

bebabo, перепиши всё в максимально читаемом виде для начала, а когда отладишь - сократишь. И то сильно усердствовать в уплотнении не стОит Улыбаюсь
Записан

blob
Гость
« Ответ #19 : 18-04-2008 14:29 » 

Столкнулся со странной проблемой. Есть класс, в нем static vector и static функция, которая работает с этим вектором, проверяя каждый объект на соответствие некому условию и если true - вырезает этот объект из вектора.

Код:
vector<Transition>::iterator t = Transition::trans.begin();
 
while(t != Transition::trans.end()){
    if(CheckShapeType((*t).GetFromShape(), sh)){
      trans.erase(t++);
    }
}

Результат - все те объекты, которые должны быть удалены - удаляются за исключением одного. Он полностью соответствует условия удаления, но не вырезается. Точнее, вырезается, если запустить цикл повторно.
Пробовал заменить вектор на список - еще хуже - уходит в бесконечный цикл.
Что здесь может быть не так?
Первое - а как оно вообще до конца доходит, когда if не возвращает true? Тогда же инкрементов не будет.
Второе - как по мне, не удаляется элемент тогда, когда два элемента, которые необходимо удалить, идут последовательно. Я тут набросал тестовый код, если его скомпилить сl.exe от 2003 студии, то вроде бы работает, но второй элемент в векторе остаётся. В 2005 студии скомпилированный код при запуске выдаёт страшные маты по поводу того, что vector iterators incompatible. По-моему справедливо, т.к. действия выполняются в таком порядке:
1) возвращается текущая позиция t
2) инкремент
3) erase
4) после erace все итераторы вектора, указывающие на элементы, лежащие после удалённого, невалидны. Это вектор, а он располагается в памяти последовательно. У него нет указателей на next и previous, как у списка.
Тестовый код:
Код:
#include <vector>
#include <iostream>

int main()
{
std::vector<int> v;
    v.push_back(1);
    v.push_back(2);
    std::vector<int>::iterator i = v.begin();
    while(i != v.end())
    v.erase(i++);
for(std::vector<int>::iterator j = v.begin(); j != v.end(); ++j)
    std::cout << *j;

попробуй использовать алгоритм std::remove_if (из заголовочного файла <algorithm>). Он перенесёт все элементы, подлежащие удалению, в конец вектора, и вернёт указатель на первый из "удалённых" элементов. Далее вызываешь
Код:
Transition::trans.erase("тот итератор, что вернул remove_if", Transition::trans.end());
и все ненужные элементы удалены.
Записан
blob
Гость
« Ответ #20 : 18-04-2008 14:35 » 

вернёт remove_if не указатель, а
Код:
vector<Transition>::iterator
Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #21 : 21-04-2008 05:03 » 

вернёт remove_if не указатель, а
Код:
vector<Transition>::iterator
в релизной сборке итератор вектора это указатель.
согласен насчет remove_if, имхо более правильный подход
Записан

Странно всё это....
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines