Q
Prefer the C++ Standard Library. Explore the Boost extensions.
If you are writing C++, then use the C++ Standard Library.
In particular, use the Standard Library collections such as std::vector, std::list and std::deque.
Why? Because the Standard Library provides a lot of useful algorithms, and goes a long way to relieving you of memory management.
In the remainder of this article, I've omitted the Standard Library namespace prefix std.
For example, rather than write std::vector, it's easier on your eyes if I write vector.
You don't have to do anything, other than acquire a C++ compiler, to have the Standard Library. It's part of the C++ language. To put it another way, if your C++ compiler doesn't include the Standard Library, then it's not a C++ compiler. If you've read this far, and you are an MDL developer, then you will most likely be using the Microsoft development tools including Visual C++. Visual C++ version 6 and subsequent revisions include implementations of the Standard Library.
With MDL, it's common to use C-style arrays for many purposes — a list of vertices, for instance, would be declared:
DPoint3d points [MAX_VERTICES];
Using pure MDL you can also use the elastic arrays provided by the Dynamic Array
mdlDArray_xxx API and by the curiously-named jmdlEmbeddedArray_xxx API.
In a C++ context, those elastic arrays are almost as redundant as C-style arrays,
because the Standard Library collections offer a better and wider choice.
Using vector provides you with an elastic array of whatever data structure you want.
As the array grows it manages memory allocation for you; as you remove elements from the array, it deallocates memory for you.
Here's an example of vector in an MDL context.
vector is used to create a contiguous list of data.
Because the Standard Library consists of templated classes, the data you put in a vector
can be pretty well any struct or class.
In the examples, we're using the MDL DPoint3d struct that you've probably used many times before.
Don't confuse vector with MDL vectors.
A Standard Library vector means an array of data.
It has nothing to do with 3D geometry.
An MDL vector means a directed line, in the
Cartesian Geometry sense.
It has nothing to do with data storage.
When using C++ templates, variable declarations can become hard to read, due to the proliferation of < and >,
which tend to generate lines of code that look like a cat just walked across your keyboard.
It becomes tedious typing std::vector<MyDataStruct>, and prone to error.
Use a typedef to clarify your code and reduce typing errors.
For example, in the code below we use a vector of DPoint3d structs.
The syntax to declare a variable of that type is:
std::vector<DPoint3d> variable;
Minimise the keyboard challenge and clarify your code!
Use typedef to make your own reusable, easy to type, classes:
typedef std::vector<DPoint3d> DPoint3dCollection;
Now, wherever you had previously to type std::vector<DPoint3d>,
you can use DPoint3dCollection. Here's the previous variable declaration using your new type:
DPoint3dCollection variable;
Suppose you want to build a list of DPoint3d vertices,
and use that list to construct a line string element.
Using the Standard Library, you would do something like this …
#include <vector>// Standard Library header for vector template classtypedef std::vector<DPoint3d> DPoint3dCollection;// typedef clarifies subsequent codeDPoint3dCollection pointList;// Elastic array of DPoint3dDPoint3d point;// Initialise some points and add to the listAddPoint (pointList, 1, 1); AddPoint (pointList, 10, 12); AddPoint (pointList, 20, 25); AddPoint (pointList, 30, 50);// List contains 4 pointsASSERT (4 == pointList.size ());
This helper function adds a point to the list.
The z argument defaults to zero to simplify the previous code.
For afficionados of const, note that C++ allows us to initialise a const value or object.
With MDL, you have to pass the address of a value because of C-calling requirements,
and the value therefore cannot be const.
This const-ness give additional freedom to your compiler to make some optimisations …
void AddPoint (DPoint3dCollection& pointList, double x, double y, double z = 0.0)
{
const DPoint3d point = { x, y, z }; // Initialise struct the C++ way
// mdlVec_fromXYZ (&point, x, y, z); // Initialise struct the MDL way
pointList.push_back (point);
}
When you've finished using your pointList, you simply stop caring about it. When it goes out of scope, <vector> cleans itself up and deallocates memory.
The above code builds a list of points.
A characteristic of vector is that data are stored contiguously, just like a C array.
That is, the data bytes at address &vector [0] look just like the data bytes of a C array.
This characteristic makes vector the most appropriate of the Standard Library containers to use when interfacing with a C-style API such as the MDL.
You can use our pointList with a C-style API, such as MDL, by passing the address of the first member of the vector.
For example, we can use the above pointList to construct a MicroStation line string.
Note that, because a vector knows its own size, we can pass the vertex list and its length like this …
MSElement line;
if (SUCCESS == mdlLine_create (&line, NULL, &pointList [0], pointList.size ()))
{
// We constructed a line string
}
Memory Management is sooo last century!
The above code fragments build a vector of DPoint3d structures.
That process uses memory allocation — but we neither know nor care how it was done, because the Standard Library handles that for us: efficiently, correctly, and invisibly.
When we've finished using the vector, we don't need to concern ourselves with memory deallocation — it happens automatically.
Many years ago, when the Standard Library was young, Microsoft wanted to introduce template collection classes to Visual C++. For various reasons, they devised their own classes for object collections CList, CArray and CMap. They provided similar collections for pointers: CTypedPtrList, CTypedPtrArray and CTypedPtrMap.
Those templated collections provided a useful service until Microsoft was able to include full support for the C++ Standard Library in Visual C++.
If you have code that uses those collections, it probably works well and you don't need to change anything.
However, for new projects you should recognise that the Standard Library provides a wider range of collection classes,
and a wide range of algorithms that operate on those classes.
Moreover, because of the availability of smart pointers (e.g. boost::shared_ptr), you can use
the Standard Library collections to store pointer-to-objects as well as objects.
Boost is the group of C++ heroes who add enormous value to the C++ Standard Library. The code they develop sometimes makes its way into the Standard Library. Boost provides new collections, algorithms, and a host of useful classes too large to enumerate here. Visit the Boost website to learn more.
Beyond the C++ Standard Library, by Björn Karlsson, is a good introduction to Boost.