Dumont Memory Management

Let's have a brief discussion about memory management issues in the DumontDLL. Normally memory management is a big bone of contention among programmers when discussing C++ programming vs programming in a higher-level language such as vbScript. Yes C++ does have its memory management issues - ie; it's not automatic - but with a little understanding it is not difficult to handle on your own.

Memory From the vbScript perspective.
When vbScript requests the DumontDLL it causes windows to bring this DLL "into existance". When that happens this DLL automatically creates a static QDumontDLL object and keeps it in memory also. This happens with the following simple code:

 dim ddll: set ddll = createObject("DumontDLL")

In actual reality, two things happen with this one vb call to createObject(). First, windows loads the DLL into memory. When that happens the QDumontDLL object is immediately created and a static (module-wide) pointer is held for it. Second, vb makes a COM call to the module's factory looking for an interface object matching the GUID number provided for from the registry. Dumont responds by creating a QCosDumontDLL object and hands vb a pointer to that object. When Dumont creates this QCosDumontDLL object it looks to see if it has been given a pointer to something called a "server" object. If not, the QCosDumontDLL object assumes the caller is requesting a handle to the QDumontDLL itself. It then acquires the pointer to the QDumontDLL. After the pointer handle is acquired, the QCosDumontDLL object checks the "server" object to see if it has a parent() assignment. If not, it assigns the parent() of that server object to the QCosDumontDLL object. This is an important step in the module memory management - pay attention! Finally the QCosDumontDLL object itself gets returned back back to the vbScript caller.

What the vbScript program now has is a newly manufacturered interface handle to a QCosDumontDLL object that has an internal pointer to a static (module-wide) QDumontDLL object. The vbScript program can call some routine - it doesn't matter - and the following things happen:

 dim ddll: set ddll = createObject("DumontDLL")       ' acquire a QCosDumontDLL handle to QDumontDLL static
 dim answer: set answer = ddll.test "This is a test"  ' call something in the module

In the above example, several (not so easy to understand at first glance) things are happening to the QCosDumontDLL object. First, vbScript dispatches control (through COM) to the QCosDumontDLL object. The first place control arrives is at the GetIDsFromNames() method of QCosDumontDLL. What this function does is look at its internal object pointer (d->) and makes a call into the Qt metaObject() system. (in short, the Qt metaObject system maintains a 'text' library of every signal, slot, property and enum contained within an object). The call to metaObject() is intended to locate an ID number for the method 'test'. If the method text name 'test' is found then it's ID number gets returned back to vbScript.

The vbScript then makes a call (through COM) to the Invoke() function of QCosDumontDLL. This is really the brain power of the dispatcher. The QCosDumontDLL::Invoke receives several arguments, one being the ID number of the method to call - the same ID number that was acquired in GetIDsFromNames(), plus an arguments-array, return-value variant pointer, exception pointers and such.

After much gyrating (you can read about that elsewhere), the QCosDumontDLL object makes the call to the hosted object member 'test' - coincident with the vbScript call 'dumDLL.test'. when that call returns, the QCosDumontDLL::Invoke function looks at the returnType (called methodType by Qt) for a pointer - and so the memory magic begins.

Any QObject method return type other than a pointer is translated directly into a vbScript compatible data-type. There's a translation coming in, and a translation going out. But, in the case of a pointer, the QCosDumontDLL assumes that what has been requested is a pointer to a Qt object.

In this case, the QCosDumontDLL manufactures a new QCosDumontDLL object with a pointer to the object returned by the Qt::Invoke method. What this basically means is the QCosDumontDLL, a COM IDispatch interface object, is being used to wrap a Qt object. This is done because the QCosDumontDLL has a QObject* to the object it is wrapping.

But, some important memory management related routines happen here. First off, a call is made into the QObject invoke method to the Qt object. If the method that is being invoked returns a pointer to another Qt object that Qt object can come back in one of two ways - parented and not parented.

Here is how Dumont is set up to handle memory. If Dumont is returning (to vb) an object pointer that has a parent() assignment, then that object's memory (and, therefore, lifetime) is being managed by Qt. If Dumont is returning an object pointer that does NOT have a parent() assignment, then Dumont has decided to leave the management of that memory for that object to vb itself.

Here's how vb gets to manage that memory. When vb gets an object pointer, what it is actually getting is a pointer to a QCosDumontDLL object. When vb is done messing with this object pointer it frees it - and this freeing action causes QCosDumontDLL.delete operation to be fired as well. The QCosDumontDLL object is destroyed.

Now, earlier, Dumont had created a new Qt object and it had decided if that object should have a parent or not. Well, this decision caused the QCosDumontDLL object to assign a new parent to this managed (wrapped) object or not. If the wrapped object has a parent then the QCosDumontDLL leaves the existing parent alone. If the wrapped object does not have a parent, then before giving control back to vb, the QCosDumontDLL object assigns itself as the parent to this Qt object.

This means that when vb is done with the object it requested, and frees it, the QCosDumontDLL object is also freed. And, because the QCosDumontDLL object assigned itself as the parent to the wrapped object, the deletion of the QCosDumontDLL wrapper causes the deletion of the object it is wrapping - thanks to Qt's object management system.

If the object that got returned to vb is the parent to other Qt object, then all of those objects will be deleted as well. This can be somewhat problemmatic if you're not careful when creating Qt objects for exposure to vb with the parenting of those objects. It's entirely possible to have a vb pointing to two Qt objects, and then delete one of those pointers which is the parent of the other only to have that second object go out of existance even when vb thinks it still has a valid pointer.

And, that's about all I can say about all of that for the moment.

~ ~ ~ ~ ~ ~
Source Code without Comments is like a Cranberry Garland
without the berries. Comment your Code!
Commence Database User Support Group Forum
~ ~ ~ ~ ~ ~
Author: Mark Petryk
Lorimark Solutions, LLC