Search code examples
visual-c++atlcstring

How to combine CString, CSimpleMap and CSimpleArray


typedef ATL::CSimpleMap<WTL::CString,WTL::CString> _Map;
ATL::CSimpleArray<_Map> g_arrMaps;
_Map map;
map.Add(WTL::CString(L"first"),WTL::CString(L"second"));
map.Add(WTL::CString(L"first2"),WTL::CString(L"second2"));
g_arrMaps.Add(map);

//another place _Map has been destructed
for(int i=0;i<g_arrMaps.GetSize();i++){
    _Map m=g_arrMaps[i];
    for(int y=0;y<m.GetSize();y++){
        ATLTRACE(m.GetKeyAt(y)); //error
    }
}

I got error when I want to trace out the data.


Solution

  • CSimpleMap has a good-for-nothing compiler-supplied copy constructor, which merely copies the pointer to its internal buffer. When you add a map to your CSimpleArray, both maps actually share the same data structure. When one goes out of scope and releases memory, it causes the other to become invalid as well. In your case, you might got lucky with accessing already freed CSimpleMap buffer, but that buffer contains CStrings, and once deleted they have released their internal buffers, namely the char arrays.

    What you can do:

    1. Avoid using CSimpleMap. It actually does a serial lookup, and it has that horrible default copy constructor. Use CAtlMap instead - its copy constructor is private, so you'll know you're doing something wrong in compile time.
    2. Have the CSimpleArray contain pointers to maps: CSimpleArray<_Map*>. This means extra memory management on your part, but then you avoid the buffer sharing.
    3. Or, you can inherit CSimpleMap or CAtlMap, and provide it a decent copy constructor.