Attaching and Detaching Objects

Creating objects

All the wrapper classes support one additional operation, the FromHandle method. This is a static method of the wrapper class, and it takes as an input argument a handle of the underlying Windows object, and returns as a result a temporary wrapper object. A permanent object is one which will not be garbage-collected during idle time.

Thus, if I simply do a GetFont, I get a reference to a temporary object. This pointer cannot be stored, because eventually the space it occupies will be reclaimed. The following code is fatally flawed:

class CMyClass : public CView {
protected:
     CFont * myFont;
};
 
// anywhere in the class implementation
myFont = GetFont();
// or
myFont = CFont::FromHandle(...);

An attempt to use the variable myFont at any later time has an excellent chance of failing in a suitably interesting catastrophic way. Perhaps an ASSERT failure, or an access fault, or simply incorrect behavior, such as no apparent font change. This is because the object was created by GetFont, added to the list of temporary objects, and later deleted. When a temporary object is deleted, the underlying Windows object is not deleted as the temporary object is seen as only a proxy.

The correct way to store a reference to an underlying object is as follows:

CFont * f = GetFont();
if(f == NULL)
    myFont = NULL;
else
   { /* attach it */
    myFont = new CFont;
    myFont->Attach(f->m_hObject);
   } /* attach it */

Note that this presumes that myFont is either NULL or its value is meaningless. If it is non-NULL, there is an excellent chance that it was already holding a valid CFont reference. You have to decide if you should delete that reference, and if you delete that reference, what should happen to the underlying HFONT. You can only do this if the variable myFont is not already holding a reference to a temporary object. In the above example, since I create a new CFont each time, I know it is not a temporary object. Two possible algorithms are:

if(myFont != NULL)
     delete myFont; // delete object and HFONT

or, alternatively

if(myFont != NULL)
    {
     myFont->Detach(); // leave HFONT alone!
     delete myFont;
     myFont = NULL;
    }

Don't forget to set the myFont member to NULL in the class's constructor!

If you should happen to delete an object which is already a temporary object, you will get an assertion failure or possibly even an access fault from deep inside MFC when it tries to delete the temporary object that had been allocated. Never delete temporary objects. Thus the following code is fatal:

CFont  * f;
f = somewindow.GetFont();
delete f;

If you get this, you will know almost immediately that you have deleted a temporary object; shortly after you return to the main message loop, you will get an assert failure.

You might also like...

Comments

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“God could create the world in six days because he didn't have to make it compatible with the previous version.”