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.
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); };
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; }
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