Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 27.01.2012, 12:51   #1
Mandrivnyk
Software Developer
Участник клуба
 
Аватар для Mandrivnyk
 
Регистрация: 01.03.2011
Сообщений: 1,098
По умолчанию map указателей на элемент контейнера

Доброе время суток -)
В общем, как обычно, возникла необходимость...

Есть структура, скажем, S
Код:
struct S
{ string str; int num; bool flag; };
И есть вектор этих структур
Код:
vector<S> vectS;
В него считываются данные их XML-файла, при этом поле str содержит уникальные (неповторяющиеся) значения.
Надо сделать отображение, которое будет хранить в качестве ключа str, а в качестве значения -- указатель на соответствующий элемент вектора vectS.
Пытаюсь сделать так:
Код:
map<string, S*> mymap;
// тут цикл по XML-файлу, данные из нод считываются во временную переменную tmpS (типа S)
    // добавляем считанную структуру в вектор
    vectS.push_back(tmpS);
    // добавляю новый элемент в map
    mymap.insert(make_pair(tmpS.str, &vectS.back()));
// конец цикла по файлу
Проверяем
Код:
map<string, S*>::iterator It;
for (It = mymap.begin(); It != mymap.end(); ++It)
    cout << It->first << "\t" << It->second << endl;
Вроде, все ок -- печатает ключи и некие адреса.
Но!
Когда я пытаюсь "достать" элемент вектора, на который указывает (?) этот адрес, получаю Segmentation fault.
При этом, если я делаю так:
Код:
cout << (*mymap["/* тут заведомо существующий ключ */"]).str << endl;
то Segmentation fault вылетает сразу.
Если же я немного видоизменю вышеприведенную печать всего map'а
Код:
map<string, S*>::iterator It;
for (It = mymap.begin(); It != mymap.end(); ++It)
    cout << It->first << "\t" << (*It->second).str << endl;
то _первую пару_ "ключ -- элемент вектора по адресу" мне выводит правильно... а вот потом опять Segmentation fault...

Где грабли?
Или мне надо брать "умные указатели"? Ну, например, вoost'овские shared_ptr?
Болтовня ничего не стоит. Покажите мне код. (c) Linus Torvalds
Помог ответ? -- Поставьте отзыв.
Выражения особой благодарности в рублевом эквиваленте отправлять сюда --> R269634919062

Последний раз редактировалось Mandrivnyk; 27.01.2012 в 16:41. Причина: Исправил опечатку vectS* --> S*
Mandrivnyk вне форума Ответить с цитированием
Старый 27.01.2012, 13:57   #2
Rififi
Старожил
 
Регистрация: 19.08.2009
Сообщений: 2,119
По умолчанию

Mandrivnyk

// добавляю новый элемент в map
mymap.insert(make_pair(tmpS.str, &vectS.back()));


а не указатель ли на локальную переменную ты запихиваешь в мап?

а вообще, наблюдается некая избыточность. str у тебя ключ, и также в структуре сидит. некошерно.
Rififi вне форума Ответить с цитированием
Старый 27.01.2012, 14:26   #3
Mandrivnyk
Software Developer
Участник клуба
 
Аватар для Mandrivnyk
 
Регистрация: 01.03.2011
Сообщений: 1,098
По умолчанию

Цитата:
а не указатель ли на локальную переменную ты запихиваешь в мап?
Вот вопрос...
Но вроде бы нет... Или есть возможность это проверить? -)
Цитата:
а вообще, наблюдается некая избыточность. str у тебя ключ, и также в структуре сидит. некошерно.
Структура считывается полностью их XML-файла. И это поле мне понадобиться позже, поскольку предполагается наличие еще одной структуры/класса с набором методов, имена которых и есть, собственно, значения этого поля.

А вообще -- возможно, это связано с особенностью vector'а -- переаллоцировать для себя память в процессе выполнения программы. Другие контейнеры (deque, list и тот же map) этого не делают...

Кстати, кроме shared_ptr есть еще и reference_wrapper от "того же производителя".
Может, кто уже работал с чем-нибудь из них?

Или вообще смотреть в сторону Pointer Container Library от все того же boost'а?
Болтовня ничего не стоит. Покажите мне код. (c) Linus Torvalds
Помог ответ? -- Поставьте отзыв.
Выражения особой благодарности в рублевом эквиваленте отправлять сюда --> R269634919062

Последний раз редактировалось Mandrivnyk; 27.01.2012 в 14:47.
Mandrivnyk вне форума Ответить с цитированием
Старый 27.01.2012, 14:46   #4
artush1984
Форумчанин
 
Аватар для artush1984
 
Регистрация: 27.04.2009
Сообщений: 184
По умолчанию

по моему в место
Код:
map<string,vectS*> mymap;
вам надо
Код:
map<string,S*> mymap;
Hа C я могy пpосто делать ошибки, на C++ я могy их наследовать!
artush1984 вне форума Ответить с цитированием
Старый 27.01.2012, 16:36   #5
Mandrivnyk
Software Developer
Участник клуба
 
Аватар для Mandrivnyk
 
Регистрация: 01.03.2011
Сообщений: 1,098
По умолчанию

Цитата:
Сообщение от artush1984 Посмотреть сообщение
по моему в место
Код:
map<string,vectS*> mymap;
вам надо
Код:
map<string,S*> mymap;
Да, конечно же... Это я тут просто опечатался. Уже исправил.
Для наглядности не копипастил с теми названиями, что у меня в проекте, а переименовал уже тут.
Вот и получилось тут так криво. Но только тут =)

А вообще -- таки да... Проблема именно с vector'ом.
Простая замена на list сразу все исправила.

Но тем не менее, если кто использовал (вдруг) упомянутые мной в предыдущем посте библиотеки -- очень бы хотелось услышать отзывы и рекомендации -)
Болтовня ничего не стоит. Покажите мне код. (c) Linus Torvalds
Помог ответ? -- Поставьте отзыв.
Выражения особой благодарности в рублевом эквиваленте отправлять сюда --> R269634919062

Последний раз редактировалось Mandrivnyk; 27.01.2012 в 16:40.
Mandrivnyk вне форума Ответить с цитированием
Старый 27.01.2012, 17:54   #6
Сыроежка
Форумчанин
 
Регистрация: 01.07.2011
Сообщений: 423
По умолчанию

Цитата:
Сообщение от Mandrivnyk Посмотреть сообщение
Да, конечно же... Это я тут просто опечатался.
А вообще -- таки да... Проблема именно с vector'ом.
Простая замена на list сразу все исправила.
По мере добавления элементов вектор может несколько раз переписывать себя из одной области памяти в другую. Если вы можете априори вычислить максимальный размер вектора, то вам надо было объявлять вектор с конструктором, принимающим этот максимальный размер вектора, либо использовать функцию-члена класса вектора reserve. Но при этом надо иметь в виду, что любое удаление из вектора элемента или вставка нового элемента после первоначального заполнения вектора приводит все указатели в отображении к недействительному виду.
Со списком у вас работает по той простой причине, что список не делает перемещение своих элементов.
Вы могли бы использовать веторк, но только в отображении хранить не указатель на элемент вектора, а индекс элемента.
При этом вам надо обечпечить синхронизацию операций по изменению последовательного контейнера и отображения.
Со мной можно встретиться на www.clipper.borda.ru

Последний раз редактировалось Сыроежка; 27.01.2012 в 17:57.
Сыроежка вне форума Ответить с цитированием
Старый 27.01.2012, 18:11   #7
Rififi
Старожил
 
Регистрация: 19.08.2009
Сообщений: 2,119
По умолчанию

Mandrivnyk

не зная полной задачи трудно сказать.
вообще, по моему опыту, для каких-либо операций с индексами чуть сложнее чем примитивные, ничего лучше чем Boost.MultiIndex не видел
Rififi вне форума Ответить с цитированием
Старый 27.01.2012, 18:20   #8
Mandrivnyk
Software Developer
Участник клуба
 
Аватар для Mandrivnyk
 
Регистрация: 01.03.2011
Сообщений: 1,098
По умолчанию

Цитата:
Сообщение от Сыроежка Посмотреть сообщение
По мере добавления элементов вектор может несколько раз переписывать себя из одной области памяти в другую. Если вы можете априори вычислить максимальный размер вектора, то вам надо было объявлять вектор с конструктором, принимающим этот максимальный размер вектора, либо использовать функцию-члена класса вектора reserve. Но при этом надо иметь в виду, что любое удаление из вектора элемента или вставка нового элемента после первоначального заполнения вектора приводит все указатели в отображении к недействительному виду.
Со списком у вас работает по той простой причине, что список не делает перемещение своих элементов.
Вы могли бы использовать веторк, но только в отображении хранить не указатель на элемент вектора, а индекс элемента.
При этом вам надо обечпечить синхронизацию операций по изменению последовательного контейнера и отображения.
Да, именно это я и имел в виду, когда описывал в первом посте возможные причины проблемы.
Размер вектора мне становится известным в процессе выполнения программы -- я же парсю XML-файл; подсчитать количество нужных нод -- вот он и размер. И да, после прочтения и заполнения вектор остается неизменным до конца отработки программы (неизменным в смысле количества элементов вектора; значения полей могут меняться, по-крайней мере, одно). Вопрос в другом -- а стОит ли это (подсчет элементов и резервирование памяти) того, чтобы использовать именно вектор?

И еще одно -- Джосьютис в своей книге "С++ Стандартная библиотека" советует смотреть именно в сторону shared_ptr, чтобы избежать потенциальных ошибок в случае, когда, например, указатель на элемент контейнера хранится в двух других независимых контейнерах -- как раз мой случай. Но у меня объекты контейнеров после инициализации (после парсинга XML-файла) остаются жить, как я написал выше, до конца работы программы. Меняется только поле в описанной структуре.
Все остальное -- не более чем "виртуальный интерфейс доступа" к этому полю и _по этому полю_ (то есть, работающий в две стороны).
Так что я не совсем уверен, нужно ли мне на самом деле использовать какие-либо "умные" указатели.
Впрочем, хуже точно не будет =)
Болтовня ничего не стоит. Покажите мне код. (c) Linus Torvalds
Помог ответ? -- Поставьте отзыв.
Выражения особой благодарности в рублевом эквиваленте отправлять сюда --> R269634919062
Mandrivnyk вне форума Ответить с цитированием
Старый 27.01.2012, 19:37   #9
Сыроежка
Форумчанин
 
Регистрация: 01.07.2011
Сообщений: 423
По умолчанию

Цитата:
Сообщение от Mandrivnyk Посмотреть сообщение
Так что я не совсем уверен, нужно ли мне на самом деле использовать какие-либо "умные" указатели.
Впрочем, хуже точно не будет =)
Я не вижу, как умные указатели вам могут помочь, так как нужна синхронизация между последовательным контейнером и отображением при их заполнении.
Вы, например, могли бы выбрать модель, когда сначала заполняете вектор, а уж затем по готовому вектору строите отображение.
Может быть вам вообще следует ограничиться одним вектором, который отсортировать по требуемому полю, а затем использовать двоичный поиск для доступа к его элементам.
Со мной можно встретиться на www.clipper.borda.ru
Сыроежка вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Реализация контейнера map. fabregas Общие вопросы C/C++ 11 19.04.2013 16:23
Как заменить элемент элемент одномерного массива? Паскаль Женька Good Помощь студентам 5 21.12.2011 00:07
Одномерный массив. Необходимо заменить последний положительный элемент на второй элемент массива кумитэ Паскаль, Turbo Pascal, PascalABC.NET 1 19.12.2011 16:44
Не добавляется элемент в map -LeV- Общие вопросы C/C++ 3 22.02.2011 19:36
Файловый ввод/вывод STL контейнера указателей farynaa Помощь студентам 0 21.05.2010 22:29