Форум программистов, компьютерный форум CyberForum.ru

Коварный map - C++

Восстановить пароль Регистрация
 
dyosick
 Аватар для dyosick
61 / 61 / 6
Регистрация: 25.08.2008
Сообщений: 178
24.07.2012, 13:31     Коварный map #1
Доброго всем дня, уважаемые форумчане!
Прошу прояснить следующий момент, почему при проходе по мапе теряется пара с ключом "4". Если флаг TExpiredNumberHandler стоит в true (на название класса прошу не обращать внимание):
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <string>
#include <map>
#include <iterator>
#include <utility>
 
class TExpiredNumberHandler
{
public:
    TExpiredNumberHandler(bool check = true) : check_on_owner_expiration(check) {};
 
    bool process(const int number) {
        if (number > 0) {
            if (!check_on_owner_expiration || (number < 10)) {
                return true;
            }
        }
        return false;
    }
    void setCheck(bool check) { check_on_owner_expiration = check; }
private:
    bool check_on_owner_expiration;
};
 
int main()
{
    TExpiredNumberHandler cb(true);
 
    std::map<int, std::string> test_map;
    test_map.insert(std::pair<int, std::string>(-9, "first"));
    test_map.insert(std::pair<int, std::string>(2, "second"));
    test_map.insert(std::pair<int, std::string>(28, "third"));
    test_map.insert(std::pair<int, std::string>(4, "fourth"));
    test_map.insert(std::pair<int, std::string>(36, "fifth"));
 
    for (std::map<int, std::string>::iterator it = test_map.begin(); it != test_map.end(); ++it) {
        std::cout << "\nProcess '" << (*it).first << "' Map size = " << test_map.size() << std::endl;
        if (cb.process((*it).first)) {
            std::cout << "Deleting..." << std::endl;
            test_map.erase(it);
        } else {
            std::cout << "Ignore..." << std::endl;
        }
    }
 
    std::cout << "Map size = " << test_map.size() << std::endl;
    std::cout << "End" << std::endl;
 
    return 0;
}
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
24.07.2012, 13:31     Коварный map
Посмотрите здесь:

map C++
C++ map<> в C, не в C++!
map C++
Map'ы C++
Map'ы C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
24.07.2012, 13:40     Коварный map #2
Я думаю, что дело в удалении. После "test_map.erase(it);" итератор становится невалидным. Как вариант - хранить два итератора : первый на прошлый, второй на текущий элементы карты.
p.s Могу ошибаться, ибо такая ошибка 100% будет при использовании, допустим, list / vector или других, но, может, в картах к этому защита есть.
Кот Ангенс
 Аватар для Кот Ангенс
317 / 267 / 37
Регистрация: 24.05.2012
Сообщений: 629
24.07.2012, 13:41     Коварный map #3
Как это "почему"? Потому что в коде так написано. Если стоит флаг, удалить числа от 0 до 10. Если нет, удалить все положительные.
dyosick
 Аватар для dyosick
61 / 61 / 6
Регистрация: 25.08.2008
Сообщений: 178
24.07.2012, 13:58  [ТС]     Коварный map #4
Цитата Сообщение от Кот Ангенс Посмотреть сообщение
Как это "почему"? Потому что в коде так написано. Если стоит флаг, удалить числа от 0 до 10. Если нет, удалить все положительные.
Конечно, спасибо, что откликнулись, но вы вообще запускали код? Результат выполнения программы следующий:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Process '-9' Map size = 5
Ignore...
 
Process '2' Map size = 5
Deleting...
 
Process '28' Map size = 4
Ignore...
 
Process '36' Map size = 4
Ignore...
 
Map size = 4
End
Как видим, пара с ключом 4 даже не поступила на обработку
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
24.07.2012, 14:03     Коварный map #5
Запустил, и я был прав. Просто твой компилятор либо хороший и переназначил указатель на следующий элемент (скипнув 4), либо плохой, и, сам того не понимая, прошелся по невалидному указателю.

(У меня критическая ошибка после удаления двойки)

p.s Вот ошибка с codepad.org
Process '-9' Map size = 5
Ignore...

Process '2' Map size = 5
Deleting...
/usr/local/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../../include/c++/4.1.2/debug/safe_iterator.h:210:
error: attempt to increment a singular iterator.

Objects involved in the operation:
iterator "this" @ 0x0xbf4c5bdc {
type = N11__gnu_debug14_Safe_iteratorISt17_Rb_tree_iteratorISt4pairIKiSsEEN15__gnu_debug_def3mapIiSsSt4lessIiESaIS4_EEEEE (mutable iterator);
state = singular;
references sequence with type `N15__gnu_debug_def3mapIiSsSt4lessIiESaISt4pairIKiSsEEEE' @ 0x0xbf4c5bdc
}

Disallowed system call: SYS_kill
Avazart
 Аватар для Avazart
6893 / 5133 / 250
Регистрация: 10.12.2010
Сообщений: 22,560
Записей в блоге: 17
24.07.2012, 14:12     Коварный map #6
Удаляя элемент в цикле итераторы становятся не действительными.

Добавлено через 3 минуты
C++
1
2
3
4
5
6
7
8
9
10
11
    for (std::map<int, std::string>::iterator it = test_map.begin(); it != test_map.end(); ++it) 
     {
        std::cout << "\nProcess '" <<  it->first << "' Map size = " << test_map.size() << std::endl;
        if (cb.process(it->first) ) 
         {
            std::cout << "Deleting..." << std::endl;
            test_map.erase(it); 
            --it;   // !!!!!!!!!!!
         } 
        else  std::cout << "Ignore..." << std::endl;    
     }
dyosick
 Аватар для dyosick
61 / 61 / 6
Регистрация: 25.08.2008
Сообщений: 178
24.07.2012, 14:13  [ТС]     Коварный map #7
Спасибо Avazart и nexen за комменты. Сам фикс:
C++
1
2
3
4
5
6
7
8
if (cb.process((*it).first)) {
    std::map<int, std::string>::iterator del_it = it;
    std::cout << "Deleting..." << std::endl;
    --it;
    test_map.erase(del_it);
} else {
    std::cout << "Ignore..." << std::endl;
}
Avazart
 Аватар для Avazart
6893 / 5133 / 250
Регистрация: 10.12.2010
Сообщений: 22,560
Записей в блоге: 17
24.07.2012, 14:15     Коварный map #8
Вывод
Код
Process '-9' Map size = 5
Ignore...

Process '2' Map size = 5
Deleting...

Process '4' Map size = 4
Deleting...

Process '28' Map size = 3
Ignore...

Process '36' Map size = 3
Ignore...
Map size = 3
End
dyosick
 Аватар для dyosick
61 / 61 / 6
Регистрация: 25.08.2008
Сообщений: 178
24.07.2012, 14:33  [ТС]     Коварный map #9
А в этом случае невалидность итератора после удаления обрабатывается корректно (или лучше сказать "так, как мне нужно"):
C++
1
2
3
4
5
for (std::map<int, std::string>::iterator it = test_map.begin(); it != test_map.end(); ++it) {
    std::cout << "\nProcess '" << (*it).first << "' Map size = " << test_map.size() << std::endl;
    test_map.erase(it);
    std::cout << "Deleted" << std::endl;
}
Результат:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Process '-9' Map size = 5
Deleted
 
Process '2' Map size = 4
Deleted
 
Process '4' Map size = 3
Deleted
 
Process '28' Map size = 2
Deleted
 
Process '36' Map size = 1
Deleted
 
Map size = 0
End
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,265
24.07.2012, 14:52     Коварный map #10
Да не обрабатывается она коректно. Сказано же- итератор недействительным станет. Но и
C++
1
it--
я бы делать не стал, ибо при
C++
1
it = test_map.begin();
непонятно куда будет итератор указывать.

++++++++++++++++++++++++++++++++++++++++

Впрочем, учитывая, что тебе нужно удалить ВСЁ, я бы сделал так:
C++
1
2
3
4
5
6
for (std::map<int, std::string>::iterator it = test_map.begin(); it != test_map.end(); ++it) {
    std::cout << "\nProcess '" << (*it).first << "' Map size = " << test_map.size() << std::endl;
}
 
std::cout << " All deleted" << std::endl;
test_map.erase(test_map.begin(), test_map.end());
Результат "так, как мне нужно" и надёжно.

++++++++++++++++++++++++++++++++++++++++
Ну, а если необходимо удалять ПОЭЛЕМЕНТНО, тогда

C++
1
2
3
4
5
6
for (std::map<int, std::string>::iterator it = test_map.begin(); it != test_map.end(); ) {
    std::cout << "\nProcess '" << (*it).first << "' Map size = " << test_map.size() << std::endl;
    test_map.erase(it);
    it = test_map.begin();
    std::cout << "Deleted" << std::endl;
}
dyosick
 Аватар для dyosick
61 / 61 / 6
Регистрация: 25.08.2008
Сообщений: 178
24.07.2012, 14:58  [ТС]     Коварный map #11
Всем спасибо за помощь
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,265
24.07.2012, 15:04     Коварный map #12
Вполне, корректно удалятся элементы 2 и 4, если тебе это и надо.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
24.07.2012, 15:11     Коварный map
Еще ссылки по теме:

C++ Как вставить map в map
Приведение map<int, B> к map<int, A> C++
C++ Map of map

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
dyosick
 Аватар для dyosick
61 / 61 / 6
Регистрация: 25.08.2008
Сообщений: 178
24.07.2012, 15:11  [ТС]     Коварный map #13
Мне это и надо было, но всё же я не учел тот случай, который Вы описали, т.е. когда элемент, который подлежит удалению, находится в начале мапы
Yandex
Объявления
24.07.2012, 15:11     Коварный map
Ответ Создать тему
Опции темы

Текущее время: 01:31. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru