Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Ассоциативные списки в MFC, как хранить объекты в CMap вместо CList 
:(
    Опции темы
mr.DUDA
  Дата 28.7.2003, 11:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 25
Всего: 232



Есть необходимость хранить объекты в ассоциативном списке - так и поиск получается быстрее, и объекты хранятся "парами", что позволяет много чего реализовать. Стандартный набор контейнерных классов MFC предоставляет класс CMap и производные для реализации такого списка (карты).
Проблема состоит в том, что УДАЛЯТЬ объекты из ассоциативного списка можно только пользуясь RemoveKey(TYPE key), что накладывает ряд ограничений. В частности, если в списке НЕСКОЛЬКО объектов с одинаковым ключом, то RemoveKey удаляет "первый" из них, кавычки - потому что невозможно заранее определить, какая из пар будет первой в списке (пары постоянно "тусуются" функцией HashKey).
Таким образом, получаем "половинчатую" функциональность в качестве списка - можно проходить по списку последовательно - "GetNextAssoc(POSITION pos, TYPE1 key, TYPE2 value)", но нельзя удалить объект из списка с пом. той-же POSITION. Но не все так грустно.

Вот пример того, как можно реализовать удаление объекта из CMapPtrToPtr, пользуясь значением POSITION (как в обычном списке CPtrList). Сразу скажу, что пример не претендует на звание самого лучшего, бОльшая часть - просто переписанный исходник "/VC98/MFC/SRC/Map_PP.cpp". Если кто-то знает, как реализовать быстрее - плз, пишите сюда или на [email protected]

map2_pp.h
Код
class CMapPtrToPtr2: public CMapPtrToPtr
{
public:
void RemoveAt(POSITION pos);
// этот метод - inline в классе CMapPtrToPtr, так что придется определить его снова
inline UINT CMapPtrToPtr2::HashKey(void* key) const
{
 return ((UINT)(void*)(DWORD)key) >> 4;
}
DECLARE_SERIAL(CMapPtrToPtr2);
};


map2_pp.cpp
Код
void CMapPtrToPtr2::RemoveAt(POSITION pos)
{
// оказывается, POSITION <==> CAssoc* для ассоциативных списков
CAssoc *pAssoc = (CAssoc *)pos;

// если pos==0xffffffff
if(pAssoc == (CAssoc*) BEFORE_START_POSITION)
{
 // find the first association
 for (UINT nBucket = 0; nBucket < m_nHashTableSize; nBucket++)
  if ((pAssoc = m_pHashTable[nBucket]) != NULL)
   break;
 ASSERT(pAssoc != NULL);  // must find something
}

// теперь ищем предыдущий CAssoc, чтобы удалить текущий
LPVOID key = pAssoc->key;

// полностью взято из BOOL CMapPtrToPtr::RemoveKey(void* key)
// (/VC98/MFC/SRC/Map_PP.cpp)
CAssoc** ppAssocPrev;
ppAssocPrev = &m_pHashTable[HashKey(key) % m_nHashTableSize];

for (pAssoc = *ppAssocPrev; pAssoc != NULL; pAssoc = pAssoc->pNext)
{
 if (pAssoc->key == key)
 {
  // remove it
  *ppAssocPrev = pAssoc->pNext;  // remove from list
  FreeAssoc(pAssoc);
  return;
 }
 ppAssocPrev = &pAssoc->pNext;
}
}


Еще раз повторюсь, это лишь то, что можно сделать пользуясь исходником MFC (грубо, коряво, но работает). Плз, если кто-то знает, киньте пример как сделать по-другому !
Thanks



--------------------
user posted image
PM MAIL WWW   Вверх
mr.DUDA
  Дата 28.7.2003, 14:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 25
Всего: 232



Кстати.

На самом деле очень удобно юзать карты.
Для сравнения:
Код
CPtrList list;
list.AddTail(new CSomeClass);
...
// то же самое только с картой
CMapStringToPtr map;
map.SetAt("Key1", new CSomeClass);
map["key2"] = new CSomeClass;


Не забывать только чистить поинтеры вручную, а то деструктор этого не делает.

Это сообщение отредактировал(а) mr.DUDA - 28.7.2003, 14:04


--------------------
user posted image
PM MAIL WWW   Вверх
TaTaP
Дата 29.7.2003, 02:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 86
Регистрация: 15.10.2002

Репутация: 1
Всего: 1



А использование классов MFC - это принципиально или просто по привычке? IMHO лучший выбор для такого рода задач - STL. Хоть и посложнее, чем MFC, но зато раз изучив, снимаешь с себя огромные проблемы в будущем. Стандартный ассоциативный контейнер в STL - map.
PM MAIL   Вверх
DENNN
Дата 29.7.2003, 10:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 3878
Регистрация: 27.3.2002
Где: Москва

Репутация: 1
Всего: 43



Да, используй STL и забей на контейнеры MFC - тебе от этого только легче жить будет
PM ICQ   Вверх
mr.DUDA
Дата 29.7.2003, 10:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 25
Всего: 232



Почитал я тут MSDN про STL, муть какая-то (уж простите).
Чем он так хорош - быстрее, что ли ?
IMHO, с контейнерами MFC можно делать все то же самое (кроме некоторых особо вредных случаев - как с приведенным примером CMap). Народ, если я неправ, покажите мне чем STL лучше.


--------------------
user posted image
PM MAIL WWW   Вверх
DENNN
Дата 29.7.2003, 11:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 3878
Регистрация: 27.3.2002
Где: Москва

Репутация: 1
Всего: 43



Я попробую, но от тебя потребуется по меньшей мере умение пользоваться шаблонами.
И так STL:
1. Уже реализованно множество задач по хранению, поиску и т.п. любой информации, которую можно описать средствами языка.
2. Вся библиотека построена на шаблонах - код более быстрый и в твоей программе компилятор использует только нужные участки кода. Кроме того, STL имеет модульную структуру и подключаются только необходимые модули.
3. Библиотека сама заботиться о резервировании и освобождении памяти под хранимые данные.
4. Все алгоритмы за последнии десятилетия были составлены и отлажены лучшими специалистами, поэтому, если рассматривать проблему в общем, то быстрее и лучше чем это уже сделано ты врядли напишешь. Т.е. твоя программа может выполнять ряд задач с большой скоростью если она использует STL.
5. Библиотека платформенно независима, значит ты можешь не зависеть (относительно конечно) от причуд МС или Борланд и компилировать (естественно грамотно составленный код) на различных системах.

Пример из жизни: я писал приложение OpenGL. Исходная информация о моделях импортировалась из файлов ~ 20Mb. При использовании MFC импорт занимал до 30 минут на каждый файл. Когда я воспользовался STL в том же алгоритме чтения файла, то время сократилось до 10-15 минут.

Кроме того, MFC из 7 студии не полностью совместимо с кодом MFC из 6 студии (Нет кучи "устарелых" методов у классов, таких как например WriteHuge у CFile, библиотека написана с массированным применением ATL, что вызывает кучу проблем CString в "старом" коде). Очень велика вероятность, что сегодня написав код, ты не сможешь через пару лет скомпилировать его на новой версии студии от МС. Вопрос: тебе это надо?
PM ICQ   Вверх
mr.DUDA
Дата 29.7.2003, 17:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 25
Всего: 232



Хорошо, я согласен в том, что STL - это супер.
Но.

Цитата
1. Уже реализованно множество задач по хранению, поиску и т.п. любой информации, которую можно описать средствами языка

В любом случае придется реализовывать конкретную задачу, algorithm'ы конечно помогают, но временные затраты на освоение намного больше, чем на написание "того же самого", пользуясь очень простыми средствами MFC;

Цитата
2. Вся библиотека построена на шаблонах - код более быстрый и в твоей программе компилятор использует только нужные участки кода. Кроме того, STL имеет модульную структуру и подключаются только необходимые модули.

Кто сказал, что CMap и CList - не шаблоны ? Разве код становится быстрее, если он генерится с подстановкой указанных типов на этапе компиляции а не при написании кода ? Опять же, MFC тож имеет модульную структуру и не всё из MFC включается в результирующий .OBJ, а только те ф-ции и классы, что были задействованы в коде;

Цитата
3. Библиотека сама заботиться о резервировании и освобождении памяти под хранимые данные.

Никто еще не освобождал от ответственности за освобождение памяти smile.gif . Если серьезно - в MFC есть переопределяемые шаблоны ф-ций типа ConstructElements, SerializeElements и т.п., специально для "создания и уборки мусора". Единственное, что требуется - соблюдать правила написания классов (д.б. производным от CObject, и необяз. иметь пару макросов для поддержки RuntimeClass+serialization). См. CObList, CObArray, CMapStringToOb и др.

С четвертым и пятым пунктами согласен (мелкомягкие не утруждают себя детальной отладкой всего, что выпускают), но опять-таки, за счет чего выигрыш в скорости ? От использования других соглашений наименования классов и функций ? Чел(ы), который написал контейнеры в MFC - разве не знаком с STL ?

Насчет седьмой версии MFC - нет, оно мне не надо. Если понадобится функциональность ATL - легче написать проект "полностью ATL", чем корябать под смешанным MFC+ATL. Набор классов MFC тем и хорош, что он полностью заточен под написание готовых, полноценных Desktop-app продуктов, и контейнеры MFC, IMHO органично дополняют остальную часть библиотеки.


--------------------
user posted image
PM MAIL WWW   Вверх
DENNN
Дата 29.7.2003, 14:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 3878
Регистрация: 27.3.2002
Где: Москва

Репутация: 1
Всего: 43



Цитата
что он полностью заточен под написание готовых, полноценных Desktop-app продуктов

MFC хорош только тем, что позволяет написать Windows приложение без создание множества строчек кода на WinAPI и более ничем. Если ты стараешься меня убедить, что MFC- это библиотека, заточенная под хранение и обработку информации, то ты очень сильно заблуждаешься. То что ты наследовал калсс в цепочке из ста родителей не избавляет тебя от остальных трудностей, но добавляет лишние тормоза и вероятность ошибки в коде.

Цитата
опять-таки, за счет чего выигрыш в скорости ? От использования других соглашений наименования классов и функций ? Чел(ы), который написал контейнеры в MFC - разве не знаком с STL ?

Цитата
Кто сказал, что CMap и CList - не шаблоны ? Разве код становится быстрее, если он генерится с подстановкой указанных типов на этапе компиляции а не при написании кода ? Опять же, MFC тож имеет модульную структуру и не всё из MFC включается в результирующий .OBJ, а только те ф-ции и классы, что были задействованы в коде;

Это говорит о том что ты не полностью представляешь себе различие шаблонов и ООП. А МС конечно с Stl хорошо знакома, просто их фишка в том, что весь код который они продают - их собственный, а если у тебя в каждой 20 строке STL (а его пока стандартом C++ не сделали), то как тогда себя гениальным называть?
Цитата
В любом случае придется реализовывать конкретную задачу, algorithm'ы конечно помогают, но временные затраты на освоение намного больше, чем на написание "того же самого", пользуясь очень простыми средствами MFC;

Давай не спорить, а говорить конкретно: какие это очень простые средства? Почитай учебники по STL, то что на STL описывается 3 строчками, на MFC может занимать несколько десятков. Что же после этого проще: научиться пользоваться шаблонами и STL или заучивать справку по мсдн и всем своим знакомым объяснять почему для сортировки ряда чисел твоей программе требуется платная бибилиотека МС?
Цитата
Никто еще не освобождал от ответственности за освобождение памяти . Если серьезно - в MFC есть переопределяемые шаблоны ф-ций типа ConstructElements, SerializeElements и т.п., специально для "создания и уборки мусора". Единственное, что требуется - соблюдать правила написания классов

Это говорит лишь о том, что ты не задумался над проблемой динамического массива. А наилучший тот вариант, который реализуется проще всего. smile.gif

P.S. Это еще поклонники борланда молчат. smile.gif
PM ICQ   Вверх
mr.DUDA
Дата 29.7.2003, 14:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 25
Всего: 232



Попробую разобраться с STL..

P.S> А насколько STL старая библиотека?


--------------------
user posted image
PM MAIL WWW   Вверх
DENNN
Дата 29.7.2003, 15:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 3878
Регистрация: 27.3.2002
Где: Москва

Репутация: 1
Всего: 43



Если мои сведения верны:
Первые реализации такого шаблонного кода были сделаны с финансов HP в середине 80-х. Затем это направление очень быстро стало развиваться. С VC6 поставляется код, созданный на базе HP, но переработанный dundas software для МС (в названии фирмы могу ошибаться) несколько лет назад. Что поставляется с 7 версии студии я не знаю, но видимо опять что то подправили.
Если по каким-то причинам тебе эта рализация не нравиться в сети можно найти множество альтернативных. Самая популярная видимо STL Port, наверное потому что как правило все выпускаемое SGI работает быстро и без неизвестных багов. Кроме того open source кое что значит ;)
PM ICQ   Вверх
mr.DUDA
  Дата 29.7.2003, 16:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 25
Всего: 232



To DENNN

Кстати, насчет различий ООП и шаблонов. wink.gif
Сравним следующий код:
Код
template< class TYPE, class ARG_TYPE >
class CList : public CObject

и
Код
template<class T, class A = allocator<T> >
class list


а также

Код
template< class TYPE, class ARG_TYPE >
class CArray : public CObject

и
Код
template<class T, class A = allocator<T> >
class vector

(то же самое для map)

Различия минимальны. В обоих случаях контейнеры - это шаблоны классов, только MFC добавляет к результирующему классу функциональность CRuntimeClass (определение класса во время выполнения и при сериализации). Конкретнее можно, что я не понимаю в ООП ? confused.gif

И насчет сотни базовых классов. Как видим из примера, базовый класс один. Мелкософт не пошла по пути Borland, делая из наследования самоцель. smile.gif

Последнее - про размер и быстродействие. Все-таки, я не до конца согласен насчет компактности STL. Глянуть только на кол-во методов, включаемых в простейший контейнер vector:

Код

       const A& al = A());
   void reserve(size_type n);
   size_type capacity() const;
   iterator begin();
   const_iterator begin() const;
   iterator end();
   iterator end() const;
   reverse_iterator rbegin();
   const_reverse_iterator rbegin() const;
   reverse_iterator rend();
   const_reverse_iterator rend() const;
   void resize(size_type n, T x = T());
   size_type size() const;
   size_type max_size() const;
   bool empty() const;
   A get_allocator() const;
   reference at(size_type pos);
   const_reference at(size_type pos) const;
   reference operator[](size_type pos);
   const_reference operator[](size_type pos);
   reference front();
   const_reference front() const;
   reference back();
   const_reference back() const;
   void push_back(const T& x);
   void pop_back();
   void assign(const_iterator first, const_iterator last);
   void assign(size_type n, const T& x = T());
   iterator insert(iterator it, const T& x = T());
   void insert(iterator it, size_type n, const T& x);
   void insert(iterator it,
       const_iterator first, const_iterator last);
   iterator erase(iterator it);
   iterator erase(iterator first, iterator last);
   void clear();
   void swap(vector x);


и сравнить с полным набором методов у CArray:
Код
template<class TYPE, class ARG_TYPE>
class CArray : public CObject
{
public:
// Construction
CArray();

// Attributes
int GetSize() const;
int GetUpperBound() const;
void SetSize(int nNewSize, int nGrowBy = -1);

// Operations
// Clean up
void FreeExtra();
void RemoveAll();

// Accessing elements
TYPE GetAt(int nIndex) const;
void SetAt(int nIndex, ARG_TYPE newElement);
TYPE& ElementAt(int nIndex);

// Direct Access to the element data (may return NULL)
const TYPE* GetData() const;
TYPE* GetData();

// Potentially growing the array
void SetAtGrow(int nIndex, ARG_TYPE newElement);
int Add(ARG_TYPE newElement);
int Append(const CArray& src);
void Copy(const CArray& src);

// overloaded operator helpers
TYPE operator[](int nIndex) const;
TYPE& operator[](int nIndex);

// Operations that move elements around
void InsertAt(int nIndex, ARG_TYPE newElement, int nCount = 1);
void RemoveAt(int nIndex, int nCount = 1);
void InsertAt(int nStartIndex, CArray* pNewArray);

// Implementation
protected:
TYPE* m_pData;   // the actual array of data
int m_nSize;     // # of elements (upperBound - 1)
int m_nMaxSize;  // max allocated
int m_nGrowBy;   // grow amount

public:
~CArray();
void Serialize(CArchive&);
#ifdef _DEBUG
void Dump(CDumpContext&) const;
void AssertValid() const;
#endif
};


Вопросик: какой из них даст более длинный код, учитывая, что среднее кол-во строк у каждого метода примерно одинаковое в CArray и vector ?
smile.gif

Мой респект, DENNN, всё-таки окончательный выбор - дело каждого, я попробую разобраться в STL и определить для себя, что все-таки лучше - тратить время на освоение абсолютно чужой формы записи, или юзать простые (все же, ОЧЕНЬ простые) MFC'шные контейнеры.


--------------------
user posted image
PM MAIL WWW   Вверх
DENNN
Дата 29.7.2003, 17:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 3878
Регистрация: 27.3.2002
Где: Москва

Репутация: 1
Всего: 43



Выбирай что хочешь. smile.gif
PM ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1752 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.