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()中則有:
int nMoveCount = m_nSize - (nIndex + nCount);
DestructElements<TYPE>(&m_pData[nIndex], nCount);
if (nMoveCount)
memmove(&m_pData[nIndex], &m_pData[nIndex + nCount],
nMoveCount * sizeof(TYPE));
m_nSize -= nCount;
可見Array採用隊列方式存儲數據,因而其內部數據元素是以物理方式順序排列的,所以檢索、順序執行GetAt()等函數的速度是相當快的。但是由於每次隊列長度變化後,數據都要重新申請內存、拷貝內存、釋放內存,因而Insert/Add/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.