Collections类族主要包括三种形式及其不同应用:
Array — CArray, CObArray, CStringArray, CPtrArray, CByteArray, CWordArray, CDWordArray, CTypedPtrArray
List — CList, CObList, CStringList, CPtrList
CMap — CMap, CTypedPtrMap, CMapPtrToPtr, CMapPtrToWord, CMapWordToPtr, CMapStringToPtr
整体比较:
属性 | 类族 | 特点 |
内存结构 | Array | 在VC源码CArray::SetSize()中可看到: TYPE* pNewData = (TYPE*) new BYTE[nNewMax * sizeof(TYPE)]; // copy new data from old memcpy(pNewData, m_pData, m_nSize * sizeof(TYPE)); // construct remaining elements ASSERT(nNewSize > m_nSize); ConstructElements<TYPE>(&pNewData[m_nSize], nNewSize-m_nSize); // get rid of old stuff (note: no destructors called) delete[] (BYTE*)m_pData; m_pData = pNewData; 而在RemoveAt()中则有: 如果你使用的数据元素尺寸相当大,而且数组的操作相当复杂,频繁(1E4以上的)使用InsertAt/SetAt/RemoveAt等,应该考虑使用CList来代替。 一个特例是PtrArray/CTypedPtrArray,其内部数据是某个数据地址,而非数据本身,所以其效率更接近CList。 |
List | 在VC源码CList::AddTail()中可看到: CNode* pNewNode = NewNode(m_pNodeTail, NULL); pNewNode->data = newElement; if (m_pNodeTail != NULL) m_pNodeTail->pNext = pNewNode; 因而List采用链表方式存储数据,因而当链表数据有所变动时,只做了一下指向变动,所以即使数据元素非常多单个数据元素也很大,执行Insert/Add/Remove的速度都很快,但是因为没有统一的Index,因而如果要找到某个元素只有遍历整个链表。 整体上说,List的使用比较繁琐,特别为小尺寸数据设计List更是得不偿失的,这也是为什么有CWordArray而没有CWordList的原因,因而在大多数情况下应该有限考虑是否可以使用Array来存储数据。 | |
Map | Map采用杂凑(Hashing)表方式来存储和检索数据,其内容包括Key和Value的双列表及其之间的映射关系表。例如在OODBLib用到的::FhtRegister <Class>()函数,在内部使用了Key=Class名称/Value=Class与数据库列的映射,从而在使用Class时只需要知道类的名字即可找到与之对应的数据库映射方法。 在下面的Characteristics表中可看到,Key的数值不可重复,即只能是唯一的(例如在上例中同一个程序中不可能有两个相同名字的类的声明),而Value可重复(不同名字的类可有完全相同的变量和函数)。 尽管杂凑表使用了高效的检索方式,大量使用CMap::LookUp()函数还是很耗时的,400 000次LookUp()执行时间大约是1秒,而同样次数的CObArray::GetAt()函数只需要0.3秒。 | |
应用技巧 | Array | ①如果在你所使用的场合中,出现下列情况之一:a.数据元素的尺寸很大b.经常需要执行Add函数(例如数据库在执行Select语句时) 则需要事先执行SetSize(int nSize,int nGrowBy)函数,事先确定大致尺寸(之后仍可增加)及每次增加时一次申请的内存数,从而避免频繁执行内存申请、复制和删除工作。 ②所有的命名中含Ptr的类都不进行删除内存的工作,需要自己完成。 ③如果在循环中涉及RemoveAt()函数,循环一定要从尾部开始,否则可能漏掉元素,例: CTypedPtrArray <CObArray,CPeople*> PeopleArray; for (int i=PeopleArray.GetSize()-1;i>=0;i--) { if (PeopleArray.GetAt(i)->Name()=="Tom") { delete PeopleArray.GetAt(i); PeopleArray.RemoveAt(i); //cy: 如果从i=0循环,则删除i后会漏掉对i-1的检查。 } } |
List | (暂缺) | |
Map | ①由于LookUp的执行速度比较慢,如果必须进行映射,可在第一此LookUp时将其地址获得并记录,此后可直接使用。参考OODBLib/COODBQuery::COODBQuery(),注意 m_cpOODBCDMap=::FhtOODBCDMapOf(aClass.CDMapName()); 语句完成了上述操作。 |
下面是MSDN中Collections: Choosing a Collection Class章节的一些性能列表及注释。
Collection Shape Features
Shape | Ordered? | Indexed? | Insert an element | Search for specified element | Duplicate elements? |
List | Yes | No | Fast | Slow | Yes |
Array | Yes | By int | Slow | Slow | Yes |
Map | No | By key | Fast | Fast | No (keys) Yes (values) |
Characteristics of MFC Collection Classes
Class | Uses C++ templates | Can be serialized | Can be dumped | Is type-safe |
CArray | Yes | Yes 1 | Yes 1 | No |
CByteArray | No | Yes | Yes | Yes 3 |
CDWordArray | No | Yes | Yes | Yes 3 |
CList | Yes | Yes 1 | Yes 1 | No |
CMap | Yes | Yes 1 | Yes 1 | No |
CMapPtrToPtr | No | No | Yes | No |
CMapPtrToWord | No | No | Yes | No |
CMapStringToOb | No | Yes | Yes | No |
CMapStringToPtr | No | No | Yes | No |
CMapStringToString | No | Yes | Yes | Yes 3 |
CMapWordToOb | No | Yes | Yes | No |
CMapWordToPtr | No | No | Yes | No |
CObArray | No | Yes | Yes | No |
CObList | No | Yes | Yes | No |
CPtrArray | No | No | Yes | No |
CPtrList | No | No | Yes | No |
CStringArray | No | Yes | Yes | Yes 3 |
CStringList | No | Yes | Yes | Yes 3 |
CTypedPtrArray | Yes | Depends 2 | Yes | Yes |
CTypedPtrList | Yes | Depends 2 | Yes | Yes |
CTypedPtrMap | Yes | Depends 2 | Yes | Yes |
CUIntArray | No | No | Yes | Yes 3 |
CWordArray | No | Yes | Yes | Yes 3 |
1. To serialize, you must explicitly call the collection object’s Serialize function; to dump, you must explicitly call its Dump function. You cannot use the form
ar << collObj
to serialize or the form
dmp
<< collObj
to dump.
2. Serializability depends on the underlying collection type. For example, if a typed pointer array is based on CObArray, it is serializable; if based on CPtrArray, it is not serializable. In general, the “Ptr” classes cannot be serialized.
3. If marked Yes in this column, a nontemplate collection class is type-safe provided you use it as intended. For example, if you store bytes in a CByteArray, the array is type-safe. But if you use it to store characters, its type safety is less certain.