I spend a lot of time debugging old code. Tracing through libraries written years ago, before the VC++ STL had reached maturity. And one of the often-frustrating aspects of this is how difficult it is to examine the contents of the old, MFC collection classes. CDWordArray, CStringArray, CMapPtrToPtr... not to mention the various templatized versions of these classes. While sometimes these can be easily replaced with newer, better-supported STL equivalents, often the effort involved outweighs the benefit.
At least for the array classes, it's only a minor inconvenience: the array pointer, and the size of the array are both readily available, and with these it's easy enough to view the contents.
But for the CMap classes, things get ugly. Internally, these objects are hash tables, with an array of buckets and each bucket a linked list. Viewing the contents of one of these maps in the debugger requires manually tracing the list of each bucket, then backing up and trying another bucket, then another... until you've found the item, or just given up.
The std::map<> class, implemented as a red-black tree, should be just as much of an annoyance to view - however, it gets flattened into what looks like an array:

Handy, eh? So enough of tracing through buckets.
Open \Program Files\Microsoft Visual Studio 8\Common7\Packages\Debugger\autoexp.dat, and at the end of the [Visualizer] section, add:
;------------------------------------------------------------------------------
; CArray
;------------------------------------------------------------------------------
CArray<*>|CDWordArray|CWordArray|CByteArray|CUIntArray|CPtrArray|CObArray|CStringArray{
preview
(
#( "[", [$c.m_nSize], "](",
#array
(
expr : $c.m_pData[$i],
size : $c.m_nSize
),
")")
)
children
(
#(
#array
(
expr : $c.m_pData[$i],
size : $c.m_nSize
)
)
)
}
Start a debug session. You should now be able to quickly examine the various CArray (CDWordArray...) objects as easily as std::vector<...>s. Note that the preview (...) section controls what's viewed in the initial DataTip or watch line, while the children(...) section controls what's displayed when you expand it.

Now for the fun one. Start with:
;------------------------------------------------------------------------------
; CMap
;------------------------------------------------------------------------------
CMap<*>|CMapPtrToPtr|CMapPtrToWord|CMapWordToPtr|CMapWordToOb|CMapStringToPtr|CMapStringToOb|CMapStringToString{
preview
(
#( "[", [$c.m_nCount], "](",
#array
(
expr : $c.m_pHashTable[$i],
size : $c.m_nHashTableSize
) : #list (
head : &$e,
next : pNext
) : $e,
")")
)
children
(
#(
#array
(
expr : $e.m_pHashTable[$i],
size : $e.m_nHashTableSize
) : #list (
head : &$e,
next : pNext
) : $e
)
)
}
Ah, now this one will save some serious time - it'll flatten the various CMap objects such that they look like arrays in the debugger. A CMap with 3000 items will show 3000 children, numbered 0-2999.

But it can still be better: each of those children is a key-value pair, specifically a CMap::CAssoc object. It'd be nice if we could get a preview of those keys and values as we scroll through those 3000 items, rather than having to expand each one...
CMap<*>::CAssoc|CMapPtrToPtr::CAssoc|CMapPtrToWord::CAssoc|CMapWordToPtr::CAssoc|CMapWordToOb::CAssoc|CMapStringToPtr::CAssoc|CMapStringToOb::CAssoc|CMapStringToString::CAssoc {
preview
(
#(
"(",
$e.key,
",",
$e.value,
")"
)
)
children
(
#(
key: $c.key,
value: $c.value
)
)
}
There! All happy.
Of course, you can write rules for your own datatypes too, if you want them to be immediately visible in the preview. For a good reference, see the excellent writeup over at virtualdub.org

