Udostępnij za pośrednictwem


Play around with .Net Dictionaries and STL maps

Last time (Adventures in interop code: explore string interop memory) we investigated sharing memory between native and managed code, or between processes.

Data structures are very useful: things like arrays, structures, lists, dictionaries, stacks, queues, etc. are used throughout programming.

In the early days of programming, if you wanted to use any of these, you’d have to write it yourself. Even with something as simple as arrays or strings, if you wanted dynamic sizing, you’d have to write the memory allocation business yourself. Yes, even strings have various implementations. CComBSTR, BSTR, wchar, CString, CAtlString, each with their own semantics.

Eventually shared libraries came along, with their own implementations of these structures, along with their slightly different behaviors. What should happen if you add an item to a dictionary twice? Should the data be maintained in sorted order? What are the sorting semantics?

Even with the first implementation of .NET, there were collection classes. Not until .Net 2.0 did Generic collections come along, so you could make a Dictionary(Of String, Integer):

        Dim MonthDict As New Dictionary(Of String, Integer)

        MonthDict("Jan") = 31

        MonthDict("Feb") = 28 ' leap?

        MonthDict("Mar") = 31

        MonthDict("Mar") = 31 ' try a duplicate entry, no prob

 

Or in C# (note the square brackets vs parens):

            var MonthDict = new Dictionary<string,int>();

            MonthDict["Jan"] = 31;

            MonthDict["Feb"] = 28;

            MonthDict["Mar"] = 31;

            MonthDict["Apr"] = 30;

In C++ nowadays, there are at least 2 implementations of some of these. See the ATL(ActiveX Template Library) containers, like CRBMap, CRBTree, CSimpleArray, CAtlArray, and the STL (Standard Template Library) implementations, like Hash_Set, Map, MultiMap, vector, in MSDN.

 

Many of these implementations are built on a RedBlack tree (hence the name RB), but many are not.

 

Not only do the behaviors differ, but even the names of the structures are different: maps vs hash sets, vs lists vs vectors vs dictionaries.

 

Often folks would implement their own structures. No doubt, the efficiencies of the various structures vary vastly.

 

Below is a sample (built on the sample code last time) showing how to use a

 

As you single step, observe that the map class shows very useful information in the Locals window. You can customize your types similarly: see Customize the VS debugger display of your data

Stepping through STL code is instructive: the code is quite terse and very difficult to understand.

 

 

 

<C++ Code>

// DoTest is a template func that does the test.

// it's a template because 2 diff map types are passed in

using namespace std;

typedef pair<CComBSTR,int> PairStringInt;

#define NSIZE 2

template <typename TMap>

void DoTest(TMap oMap, CComBSTR bstrType)

{

      for (int nItem = 0 ; nItem < NSIZE; nItem++) // 2nd time through adds dupes, no prob: ignored

      {

            // as you single step through here, observe the value of

            // oMap in the Locals window!

            oMap.insert(PairStringInt (CComBSTR("Jan"),31));

            oMap.insert(PairStringInt (CComBSTR("Feb"),28));

            oMap.insert(PairStringInt (CComBSTR("Mar"),31));

            oMap.insert(PairStringInt (CComBSTR("Apr"),30));

            oMap.insert(PairStringInt (CComBSTR("May"),31));

            oMap.insert(PairStringInt (CComBSTR("Jun"),30));

            oMap.insert(PairStringInt (CComBSTR("Jul"),31));

            if (nItem == 0)

            {

                  // declare an iterator

                  TMap::const_iterator it;

                  // now iterate through the collection

                  for (it = oMap.begin() ; it != oMap.end() ; it++)

                  { // note they're sorted!

                        wchar_t buf[1000];

                        CComBSTR strOutput(bstrType);

                        strOutput.Append(L" ");

                        strOutput.Append(it->first);

                        strOutput.Append(L" ");

                        _itow_s(it->second, buf,10, 10);

                        strOutput.Append(buf); // hi Crescens2k

                        strOutput.Append(L"\n");

                        OutputDebugString(strOutput);

                  }

            }

      }

      oMap.clear();

}

STDMETHODIMP CTestInterop::Test(BSTR str, long *pRetval)

{

      // single step through and observe the Locals window

      //some of this verbosity can be reduced via more typedefs

      // first we create a map object

      map<CComBSTR,int> MonthDict;

      DoTest(MonthDict,L"Using a map");

      multimap<CComBSTR, int> MultiMapMonthDict;

      DoTest(MultiMapMonthDict, "Using a multimap");

      return S_OK;

}

 

</C++ Code>

 

 

 

 

 

 

 

See also:

How to: Convert from a .NET Collection to a STL/CLR Container

multimap (STL)

map (STL)

You can develop code faster

Article on allocators: https://www.ddj.com/cpp/184403759