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

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

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

WWW
« : 19-06-2008 07:19 » 

Что вообще из себя представляет итератор? Объект?

Код: (C++)
void * p = (void*)(map_order_worker_t::iterator)workerTypes.find(code);

Цитата
Cannot cast from '_STL::_Rb_tree_iterator<_STL::pair<const AnsiString,_order_worker_t>,_STL::_Const_traits<_STL::pair<const AnsiString,_order_worker_t> > >' to 'void *'

Суть проблемы в том, что у меня есть некий список элементов (структура элемента и списка не изменяемая!), где с каждым элементом ассоциирован указатель void* (входит в структуру элемента). Еще у меня есть std::map<AnsiString, struct ...>. Я бы хотел как-то связать каждую строку списка с элементом карты, используя этот void*.

Не делать же присвоение (void*)&(workerTypes.find(code)) ...
Записан

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

ru
Offline Offline

« Ответ #1 : 19-06-2008 07:38 » 

RXL, итератор это объект

суть проблемы не понял ))) ИМХО очень запутанно написано...
Код:
map_order_worker_t::iterator iter = workerTypes.find(code);
void * p = iter.second;
просто в мапе итератор это объект пара (pair) в отличии от не ассоциативных контейнеров. Вот у этой пары есть первый и второй объекты (если ничего не забыл). Первый вроде ключ (у тебя это строка), второй это элемент данных, т.е. твоя структура, лучше в мапе (а точнее в любом контейнере хранить указательна структуру или класс, так будет меньше проблем и работать будет быстрее, потому что будет меньше переприсваиваний да + можно в перспективе хранить наследников)

Если пояснения не достаточно, а я так понимаю, что так оно и есть, напиши подробнее суть проблемы и желательно с кодом
« Последнее редактирование: 19-06-2008 07:45 от lapulya » Записан

С уважением Lapulya
RXL
Технический
Администратор

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

WWW
« Ответ #2 : 19-06-2008 07:49 » 

lapulya, да, наверно путано. Попробую еще раз.

Имеем:
1. Некий объект, содержащий список элементов. Каждый элемент имеет в своем составе "бесхозный" указатель void*, которым можно распоряжаться по своему усмотрению.
2. Созданные мной структура
Код: (C++)
typedef struct
{
  ...
} map_order_worker_t;
и карта
Код: (C++)
typedef std::map<AnsiString, order_worker_t> map_order_worker_t;

Нужно что-то поместить в "бесхозный" указатель каждого элемента списка, что поможет найти нужный элемент карты.

Если бы карты была вида std::map<int, ...>, то легко приводим int к void* и обратно. А тут - строка.
Записан

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

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

WWW
« Ответ #3 : 19-06-2008 07:53 » 

Я так и думал, что объект...

Если я понимаю правильно, map::find(key) возвращает объект автоматического класса хранения, который я могу только скопировать, но сохранять ссылку на него бессмысленно.

Ясно. Буду сохранять результат &workerTypes[code].
« Последнее редактирование: 19-06-2008 07:56 от RXL » Записан

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

ru
Offline Offline

« Ответ #4 : 19-06-2008 07:55 » 

RXL,
нет тут как раз все хорошо, мапа это ассоциативный контейнер и ссылки на итераторы хранить можно (ну естественно они валидны до момента когда данный элемент не удаляется из мапы)
Записан

С уважением Lapulya
RXL
Технический
Администратор

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

WWW
« Ответ #5 : 19-06-2008 07:58 » 

lapulya, спасибо.
Компилятор скушал и даже работает.
Записан

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

ru
Offline Offline

« Ответ #6 : 19-06-2008 08:00 » 

RXL,
первые два пункта понял (про структуру внутри которой есть void *) дальше ты говоришь про список... а где он и как объявлен (или ты под списком подразумеваешь мапу)?

Далее вижу объявление мапы у которой ключем объявлена строка, но тебе это не надо (или она уже есть поскольку код не совсем твой)?

Вижу что тебе нужна своя мапа для быстрого поиска структур с ключом int (кстати если это не является требованием, то объяви ключем void * зачем лишние приведения) , тогда ща код наблосаю
Записан

С уважением Lapulya
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #7 : 19-06-2008 08:08 » 

RXL,
вот тебе

Код:
struct A
{
void * p;
};

typedef std::map<void*, A*> Map;

void main ()
{
Map m;

void * key;
Map::iterator iter = m.find(key);
A * a = iter->first;
}
Записан

С уважением Lapulya
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #8 : 19-06-2008 08:12 » 

Точнее так
   A * a = iter->second;
Записан

С уважением Lapulya
RXL
Технический
Администратор

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

WWW
« Ответ #9 : 19-06-2008 09:25 » 

lapulya, еще короче:

1. присвоить итератор карты указателю void.
2. присвоить итератору карты результат п.2.

it->second - это понятно, а вот сам итератор сохранить...
Записан

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

ru
Offline Offline

« Ответ #10 : 19-06-2008 09:42 » 

RXL,
а) нет, итератор карты присвоить указателю void нельзя (как мы выяснили это объект)
б) присвоить итератору карты результат п.2 (я так понимаю это ты про структуру) нельзя, можно ее присвоить iter->second, это можно, правда при условии что ты не поменяешь ключь (ключь менять нельзя, ни под каким видом)
в) сам итератор хранить можно, он будет валиден до тех пока не погибнет мапа или элемент мапы на которую он косвенно ссылается

Все же не рекомендую хранить в контейнере объекы, лучше указатели на объекты...

да, кстати, надо обязательно делать проверочку, т.е. мой пример на самом деле такой
Код:
struct A
{
void * p;
};

typedef std::map<void*, A*> Map;

void main ()
{
Map m;

A * a = 0;
A b;
void * key;
Map::iterator iter = m.find(key);
if (iter != m.end())
{
a = iter->second; // итератор iter можно хранить
iter->second = &b; // это нормально и законно
iter->first = 0; // это не пропустит компилятор (ключ менять нельзя)
}
}
Записан

С уважением Lapulya
RXL
Технический
Администратор

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

WWW
« Ответ #11 : 19-06-2008 09:48 » 

Пока решил хранением указателя на it->first, т.к. ключ тоже нужен.

lapulya, результат пункта 2 - это опечатка - конечно п.1. - тот самый void *.

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

Забудь все, что я писал!!! Никаких структур!
Нужно:
1.  void * = it
2. it = void *

Короче, ясно - мои надежды обрушились, итератор до void* не ужимается, жизнь кончена...  :'(
« Последнее редактирование: 19-06-2008 15:08 от RXL » Записан

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

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


« Ответ #12 : 19-06-2008 10:13 » 

Рома, а если объектов меньше или равно 0xffff , то два указателя можно таки в один void* запузырить Улыбаюсь Жизнь продолжается ?
Записан

lapulya
Молодой специалист

ru
Offline Offline

« Ответ #13 : 19-06-2008 10:16 » 

RXL, погоди, погоди... ничего не кончено, ща все разрулим.

надо просто над задачей поковыряться,чуть по подробнее расскажи зачем в структуре хранить ссылку (косвенную, это я по итератор) на себяже в мапе?
Записан

С уважением Lapulya
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #14 : 19-06-2008 10:17 » 

Алексей1153++, он не указатель в void * запузырить хочет а целый объектище!!!
Записан

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

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


« Ответ #15 : 19-06-2008 10:23 » 

lapulya, я так понял, он хочет именно указатель сохранить, а сам итератор идёт лесом Улыбаюсь
Записан

lapulya
Молодой специалист

ru
Offline Offline

« Ответ #16 : 19-06-2008 10:25 » 

Алексей1153++, тогда я не понял... указатель на что? на сам объект? так его и хранить не надо он this для данной структуры
Записан

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

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


« Ответ #17 : 19-06-2008 10:37 » 

lapulya,
Цитата: Рома
Суть проблемы в том, что у меня есть некий список элементов (структура элемента и списка не изменяемая!)
при чём тут сам объект ? this не рулит в данном случаем. Впрочеи, придёт Рома и сам скажет, правильно я предположил или нет )
Записан

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

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


« Ответ #18 : 19-06-2008 10:39 » 

ещё (если структура программы позволяет) можно создать дополнительный массив (размером как и список) с какими угодно структурами, на которые и настраивать void* , а в элементы той структуры сохранять итератор полностью
Записан

Антон (LogRus)
Глобальный модератор

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


WWW
« Ответ #19 : 19-06-2008 11:08 » 

Положи всё в вектор отсортируй в релизе итератор вектора, есть указатель.
Записан

Странно всё это....
Dimka
Деятель
Команда клуба

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

« Ответ #20 : 19-06-2008 12:27 » 

RXL, мне кажется, проблема в том, что ты * рассматриваешь как признак указателя, а в итераторах STL на самом деле это перегруженный оператор, предоставляющий доступ к содержимому итератора. В некотором смысле итератор указыват на хранимый в контейнере объект, поэтому используется такой синтаксис, но сам итератор в памяти является объектом, а не указателем. Поэтому приведение типа к (void *) не работает.
« Последнее редактирование: 19-06-2008 12:37 от dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Dimka
Деятель
Команда клуба

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

« Ответ #21 : 19-06-2008 12:33 » 

Ну да
Код: (C++)
#include <iostream>

using namespace std;

class X
{
private:

    int x;

public:

    X() :
        x(3)
    {}

    int operator*()
    {
        return this->x;
    }
};

int main()
{
    X x;
    cout << *x << endl;
    void *y = (void *)x; // error C2440: 'type cast' : cannot convert from 'X' to 'void *'
    return 0;
}
Если закомментировать проблемную строчку, то всё работает - на экране появится "3".
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
RXL
Технический
Администратор

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

WWW
« Ответ #22 : 19-06-2008 16:02 » 

LogRus, это понятный метод, но такая косвенность неудобна.



dimka, моя проблема в том, что шаблоны меня путают и пугают. STL я начал применять сравнительно недавно - года полтора-два назад. Я не могу понять, что я могу хранить после выхода из области видимости, а что нет (сами коллекции, естественно, имеют видимость больше - класс или static в классе).



В общем, расскажу в деталях...

Есть БД. Есть проект на BuilderC++. Много GUI. Проекту более 8 лет.
Типовая ситуация: комбобокс или табличка. В табличке (или комбобоксе) некий текст. Юзер что-то выбрал, где-то кликнул и должон быть результат.

Данные состоят из ID (PK) (обычно - числа, символа, строки) и чего-то еще. Обычно в GUI-компоненты помещаются понятные пользователю данные, а не ID. В табличку в отдельный столбец можно и ID положить, но юзер будет видеть его, а это когда хорошо, а когда - нет.

Мои предшественники практиковали такие методы, как по onClick выбрать из базы строку по тексту одного из полей (часто - не уникальному), используя теже данные, что и для визуализации. Еще практиковали хранение ID в визуализируемых данных и обращение к ID по номеру столбца в таблице. Я эту гадость пресек и отделил данные от визуализации.
Обычно - создаю структуру, которая содержит данные для обработки и map или vector для создания коллекции таких структур. Чтобы связать GUI и карту (чаще карту, чем вектор), я использую то самое свойство компонент, которое позволяет сохранять один произвольный указатель на каждый элемент GUI-компонента. Указатель имеет тип TObject*, но мне на него пофиг и я храню в нем целые типы (приведением тип*<->void*<->int ) или указатели. Указатели менее предпочтительны, т.к. при работе с целыми значениями легче контролировать неверное значение, чем при работе с указателями.

Но некоторые таблицы БД, которые мне достались по наследству, используют в качестве PK тестовые поля.
Мне хотелось бы, чтобы все, что я пишу в этой программе, было максимально однотипно, чтобы как я сам, так и мои последователи не мучались над каждым куском кода, а только над первыми (пока не привыкнут к стилю). По этому я взял тот же принцип: загружаю справочники (или списки данных) в виде map, все GUI-компоненты-списки связываю со справочниками. Нужно хранить ключ справочника...
Когда ключ - целое число - проблем нет, т.к. int легко приводится к void* и наоборот. Реже попадаются таблицы с PK в виде 1 символа - это тоже переваримо. Теперь попалась таблиица, где PK в виде переменной строки до 16 символов. Вот тут я и застрял - подход дал сбой: сделать строку ключем карты легко, а сохранить в виде void* удается либо указатель на ключ, либо указатель на значение карты.
Я использовал указатель на ключ. Но хотелось бы хранить указатель на итератор: это позволит снизить расходы на поиск элемента и оставит возможность получения значения ключа. Да и просто удобнее и однотипнее будет...
« Последнее редактирование: 19-06-2008 16:07 от RXL » Записан

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

ru
Offline Offline

« Ответ #23 : 19-06-2008 17:52 » 

RXL, А почему нельзя типа так

Код:
class GUIObject
{
public:
void * userData;
};

struct DataElement
{
std::string key;
DataElement(const char * _key) : key(_key) {}
};

typedef std::map<const std::string, DataElement*> Table;


void main ()
{
Table table;
DataElement element("PK");
table.insert(Table::value_type(element.key, &element));

GUIObject * object;
object->userData = (void *)(&element.key);

Table::iterator iter = table.find(*((std::string *)object->userData));
if (iter != table.end())
{
// делаем свое черное дело...
}
}

ну или что то в этом роде.

Для того чтобы поберечь память можно например в мапу отдавать поинтер на строку из элемента и переопределить функцию меньше для мапы
Записан

С уважением Lapulya
Dimka
Деятель
Команда клуба

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

« Ответ #24 : 19-06-2008 18:12 » 

Цитата: RXL
Я не могу понять, что я могу хранить после выхода из области видимости, а что нет
Всегда думал, что то, что можно хранить то, что создано в куче, а нельзя хранить то, что создано в стеке. Для простоты всегда считаю, что созданное через new хранится в куче, остальное - в стеке. Соответствующим образом подбираю и типы.

Не проще ли реализовать (или воспользоваться чьим-нибудь) особый контейнер (не в смысле коллекций STL, а в смысле хранилища) типа варианта с набором методов для разных интерпретаций хранимого значения? Благо, union-типы позволяют в таких случаях эффективно работать с памятью.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
RXL
Технический
Администратор

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

WWW
« Ответ #25 : 19-06-2008 18:25 » 

lapulya, сложно пишешь Ага Я сейчас реализовал как p = (void*)&it->first - как раз ссылку на ключ и храню.

Кстати, если я произведу какие-либо действия с картой (добавления/удаления), которые не приведут к удалению элемента, на ключ которого я ссылаюсь, останется ли валидным указатель на ключ?
Записан

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

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

WWW
« Ответ #26 : 19-06-2008 19:20 » 

dimka, метод map::find(key) возвращает объект. Требования удалять его через delete нет, статическим он тоже не является. Что остается? - Автоматический (стековый). Соответственно, делаю вывод, что на него нельзя передавать ссылки выше по иерархии, за пределы видимости блока. Логично рассуждаю?
Записан

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

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

« Ответ #27 : 19-06-2008 19:56 » 

Цитата: RXL
Кстати, если я произведу какие-либо действия с картой (добавления/удаления), которые не приведут к удалению элемента, на ключ которого я ссылаюсь, останется ли валидным указатель на ключ?
Я бы не полагался. Согласно принципу инкапсуляции объект map имеет право делать всё, что не противоречит его интерфейсу.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Антон (LogRus)
Глобальный модератор

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


WWW
« Ответ #28 : 20-06-2008 04:05 » 

RXL
1. зайди на www.cplusplus.com потыкай в методы мапы там пишут какой мето приводит к инвалидации итераторов
например, push_back вектора может инвалидировать все итераторы, указатели и ссылки на элементы, а push_back дека инвалидирует только итераторы.

2. итераторы почти всегда передаются по значению(очень редко возникает необходимость передавать по ссылке), получая итератор не нужно его удалять или удалять элемент на который он ссылается(итератор не владелец элемента, владелец контейнер). Про итераторы потоков отдельная песня, например, двигая итератор потока(ifstream) ты двигаешь все итераторы полученные у потока.

что касается твоей проблемы, то я вероятно бы попробовал хранить указатели на объекты, а не ключи, а в идеале унаследовался бы от TObject и создал бы класс хранящий в себе итератор, ключ или что-нибуть еще(по ситуации, например ссылку на контейнер + ключ), т.к. на мой взгляд все остальные способы, выглядят, как заплатки.
Записан

Странно всё это....
RXL
Технический
Администратор

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

WWW
« Ответ #29 : 20-06-2008 04:15 » 

LogRus, спасибо, почитаю.

Создание объекта от TObject тоже выглядит заплаткой. При чем - более трудоемкой. Это я уже проходил.
Целые же идентификаторы имеют массу преимуществ над указателями на объекты. Главный недостаток объекта - его нужно уничтожить.
« Последнее редактирование: 20-06-2008 04:18 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Страниц: [1] 2  Все   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines