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

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
dyosick
61 / 61 / 6
Регистрация: 25.08.2008
Сообщений: 178
#1

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

24.07.2012, 13:31. Просмотров 871. Ответов 12
Метки нет (Все метки)

Доброго всем дня, уважаемые форумчане!
Прошу прояснить следующий момент, почему при проходе по мапе теряется пара с ключом "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;
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
24.07.2012, 13:31
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Коварный map (C++):

Обращение к элементам vector, который находится в map, находящийся в map - C++
Всем добрый день! Имеется такой контейнер. Как обращаться к элементам вектора и как пушбэчить его? map &lt;int,map&lt;int,vector&lt;int&gt; &gt;...

Возможно ли создать контейнер std::map, в котором в качестве значения была бы ссылка на std::map? - C++
Здравствуйте. Возможно ли создать контейнер std::map, в котором в качестве значения была бы ссылка на std map? Например: std::map...

Как вставить элемент и вывести элементы на экран в map<string, map<string,int>> ? - C++
У меня есть map&lt;string, map&lt;string,int&gt;&gt;, в него надо добавить элементы (типа Ivanov potato 200) Использовать именно map&lt;string,...

Как вставить map в map - C++
есть такой map map &lt; INT64 , map &lt;INT64 , map&lt; wArray , int &gt; &gt; &gt; tMenu; как его заполнить? пробовал так ...

Emplace в std::map. Как добавить элемент в std::map без копирования? - C++
здравствуйте... есть ли способ не писать так: std::map&lt;int, char&gt; ksa; ksa.emplace(std::piecewise_construct, ...

Приведение map<int, B> к map<int, A> - C++
class A {}; class B : public A {}; unordered_map&lt;int, shared_ptr&lt;B&gt; &gt; bs; Как привести bs к unordered_map&lt;int, shared_ptr&lt;A&gt;...

12
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
24.07.2012, 13:40 #2
Я думаю, что дело в удалении. После "test_map.erase(it);" итератор становится невалидным. Как вариант - хранить два итератора : первый на прошлый, второй на текущий элементы карты.
p.s Могу ошибаться, ибо такая ошибка 100% будет при использовании, допустим, list / vector или других, но, может, в картах к этому защита есть.
1
Кот Ангенс
317 / 267 / 38
Регистрация: 24.05.2012
Сообщений: 629
24.07.2012, 13:41 #3
Как это "почему"? Потому что в коде так написано. Если стоит флаг, удалить числа от 0 до 10. Если нет, удалить все положительные.
0
dyosick
61 / 61 / 6
Регистрация: 25.08.2008
Сообщений: 178
24.07.2012, 13:58  [ТС] #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 даже не поступила на обработку
0
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
24.07.2012, 14:03 #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
0
Avazart
Эксперт С++
7213 / 5385 / 286
Регистрация: 10.12.2010
Сообщений: 23,789
Записей в блоге: 17
24.07.2012, 14:12 #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;    
     }
0
dyosick
61 / 61 / 6
Регистрация: 25.08.2008
Сообщений: 178
24.07.2012, 14:13  [ТС] #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;
}
0
Avazart
Эксперт С++
7213 / 5385 / 286
Регистрация: 10.12.2010
Сообщений: 23,789
Записей в блоге: 17
24.07.2012, 14:15 #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
1
dyosick
61 / 61 / 6
Регистрация: 25.08.2008
Сообщений: 178
24.07.2012, 14:33  [ТС] #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
0
kravam
быдлокодер
1695 / 882 / 45
Регистрация: 04.06.2008
Сообщений: 5,467
24.07.2012, 14:52 #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;
}
1
dyosick
61 / 61 / 6
Регистрация: 25.08.2008
Сообщений: 178
24.07.2012, 14:58  [ТС] #11
Всем спасибо за помощь
0
kravam
быдлокодер
1695 / 882 / 45
Регистрация: 04.06.2008
Сообщений: 5,467
24.07.2012, 15:04 #12
Вполне, корректно удалятся элементы 2 и 4, если тебе это и надо.
0
dyosick
61 / 61 / 6
Регистрация: 25.08.2008
Сообщений: 178
24.07.2012, 15:11  [ТС] #13
Мне это и надо было, но всё же я не учел тот случай, который Вы описали, т.е. когда элемент, который подлежит удалению, находится в начале мапы
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
24.07.2012, 15:11
Привет! Вот еще темы с ответами:

Работа с map<string, map<string, string>> - C++
Всем привет! Что-то запарился в неожиданном месте... Есть тип данных, который выглядит так: map&lt;string, map&lt;string,string&gt;&gt; Мне...

map - C++
объясните пожалуйсто как это работает, почему тут &lt;string, int, less&lt;string&gt;&gt; так много перемееных #include &lt;map&gt; #include &lt;string&gt; ...

map<> в C, не в C++! - C++
всем привет! обращаюсь как Вам, так как не могу найти ответ в инете. если локанично: нужен map в C. в C++ уже есть класс и...

Map'ы - C++
Здравствуйте! Пожалуйста объясните как пользоваться мапами? Реализация, считывание и т.д


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

Или воспользуйтесь поиском по форуму:
13
Yandex
Объявления
24.07.2012, 15:11
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru