RAII applied to MDL memory allocation/deallocation

Resource Acquisition Is Initialisation ( RAII ) is a C++ idiom. You'll find it referenced on many web sites.

Here's an example applied to MicroStation using the MDL and the mdlModelRefIterator_api. This API lets you iterate a DGN model's attachments. As with many of MDL's C-style memory allocators, you must remember to deallocate the iterator manually in your C code. Wouldn't it be useful if your code could handle that deallocation automatically?

With C++, you can use the RAII idiom with a class constructor and destructor. The constructor creates the MDL iterator and the destructor deallocates that iterator automatically. Your calling code is simplified, and you can't forget to deallocate memory. Your code becomes more robust with little effort.

ModelRefIterator.h

Here's the CModelRefIterator class header (ModelRefIterator.h) …

 #include <mstypes.h>
//////////////////////////////////////////////////////////////////////
/// <summary> CModelIterator exists to enumerate referenced models </summary>
/// <remarks> The ModelRefIterator is destroyed automatically in the destructor.< /remarks>

class CModelRefIterator
{
   ModelRefIteratorP iterator_;

public:
   UInt32 ElementCount () const;
   bool Valid () const { return NULL != iterator_; }
   DgnModelRefP GetFirst () const;
   DgnModelRefP GetNext () const;
   explicit CModelRefIterator (bool refs);
   explicit CModelRefIterator (int scanPolicy);
   ~CModelRefIterator ();


private:
   // Private copy constructor and assignment operator prevent copying
   // (declared but not implemented)

   CModelRefIterator (const CModelRefIterator& other);
   CModelRefIterator& operator=(const CModelRefIterator& other);
};

ModelRefIterator.cpp

Here's the CModelRefIterator class implementation (ModelRefIterator.cpp) …

 #include "ModelRefIterator.h"
#include <msdgncache.fdf>
#include <msdgnmodelref.fdf>
#include <modelindex.fdf>
//////////////////////////////////////////////////////////////////////
CModelRefIterator::CModelRefIterator   (int scanPolicy)
:  iterator_ (NULL)
{
  mdlModelRefIterator_create (&iterator_, ACTIVEMODEL, scanPolicy, 0);
}
//////////////////////////////////////////////////////////////////////
CModelRefIterator::~CModelRefIterator   ()
{
  mdlModelRefIterator_free (&iterator_);
}
//////////////////////////////////////////////////////////////////////
DgnModelRefP   CModelRefIterator::GetFirst   () const
{
  return mdlModelRefIterator_getFirst (iterator_);
}
//////////////////////////////////////////////////////////////////////
DgnModelRefP   CModelRefIterator::GetNext   () const
{
  return mdlModelRefIterator_getNext  (iterator_);
}
//////////////////////////////////////////////////////////////////////
UInt32   CModelRefIterator::ElementCount () const
{
  UInt32   nElements = 0;
  DgnModelRefP   modelRef = GetFirst ();
  nElements = dgnCache_getElementCount (mdlModelRef_getCache (modelRef), DGNCACHE_SECTION_GRAPHIC_ELMS);
  while (NULL != (modelRef = GetNext ()))
  {
    nElements  += dgnCache_getElementCount (mdlModelRef_getCache (modelRef), DGNCACHE_SECTION_GRAPHIC_ELMS);
  }
  return nElements;
}

Example Usage

Using the class is simpler than calling the MDL functions it wraps. For example …

 const bool& WantRefs = true;
CModelRefIterator attachments (WantRefs);
DgnModelRefP attachment = attachments.GetFirst ();
while (attachment.IsValid ())
{
   // Do something with attachment
  attachment = attachments.GetNext ();
}

Regards, Jon Summers
LA Solutions

Anonymous