Programming Guide: Creating and Releasing Objects

# Programming Guide

## Creating and Releasing Objects

This section discusses how your part editor allocates and releases OpenDoc objects, and how it should release unneeded memory when requested to do so by OpenDoc.

### Factory Methods

Any OpenDoc object that you instantiate must be created by a factory method, a method of one class used to create an instance of another class. You should never use C++ new operator, for example, to create an object of an OpenDoc class (except for subclasses, such as ODExtension, through which you extend OpenDoc and for which your part is the factory).

Table 12 lists the factory methods you should use to instantiate any of the OpenDoc classes whose objects your part editor might ever need to create. The table lists methods that create new objects as well as those that return previously created objects, whether currently in memory or stored persistently. Your own part editor has the factory methods for the classes ODEmbeddedFramesIterator and any of its own extension objects. ODDraft has the factory method for ODPart and any of its subclasses, including your part editor.

Table 12. Factory Methods for OpenDoc Classes

    Object to be Created

    Class and Factory Method

    ODCanvas

    ODFacet::CreateCanvas
    ODWindowState::CreateCanvas

    ODContainer

    ODStorageSystem::CreateContainer
    ODStorageSystem::AcquireContainer

    ODDesc

    ODNameResolver::GetUserToken

    ODDocument

    ODContainer::AcquireDocument

    ODDraft

    ODDocument::CreateDraft
    ODDocument::AcquireDraft

    ODDragItemIterator

    ODDragAndDrop::CreateIterator

    ODEmbeddedFramesIterator (subclass)

    ODPart::CreateEmbeddedFramesIterator

    ODExtension (subclass)

    ODObject(subclass)::AcquireExtension
    (usu.ODPart(subclass)::AcquireExtension)

    ODFacet

    ODFacet::CreateEmbeddedFacet
    ODWindowState::CreateFacet

    ODFacetIterator

    ODFacet::CreateFacetIterator

    ODFocusOwnerIterator

    ODArbitrator::CreateOwnerIterator

    ODFocusSet

    ODArbitrator::CreateFocusSet

    ODFocusSetIterator

    ODFocusSet::CreateIterator

    ODFrame

    ODDraft::CreateFrame
    ODDraft::AcquireFrame

    ODFrameFacetIterator

    ODFrame::CreateFacetIterator

    ODLink

    ODDraft::AcquireLink

    ODLinkIterator

    ODDraft::CreateLinkIterator

    ODLinkSource

    ODDraft::CreateLinkSource
    ODDraft::AcquireLinkSource

    ODLinkSourceIterator

    ODDraft::CreateLinkSourceIterator

    ODLinkSpec

    ODDraft::CreateLinkSpec

    ODMenuBar

    ODMenuBar::Copy
    ODWindowState::AcquireBaseMenuBar
    ODWindowState::AcquireCurrentMenuBar
    ODWindowState::CopyBaseMenuBar

    ODNameSpace

    ODNameSpaceManager::CreateNameSpace
    ODNameSpaceManager::HasNameSpace

    ODObjectIterator

    ODObjectNameSpace::CreateIterator

    ODPart (subclass)

    ODDraft::CreatePart
    ODDraft::AcquirePart

    ODPlatformTypeList

    ODStorage::CreatePlatformTypeList

    ODPlatformTypeListIterator

    ODPlatformTypeList::
    CreatePlatformTypeListIterator

    ODPopup (for OS/2 and Windows)

    ODPopup::CopyPopup
    ODWindowState::CopyBasePopup

    ODSettingsExtension

    ODPart::AcquireExtension

    ODShape

    ODShape::Copy
    ODShape::CopyFrom
    ODShape::NewShape
    ODFrame::CreateShape
    ODFacet::CreateShape

    ODShellPlugIn

    ODPart::AcquireExtension

    ODStorageUnit

    ODDraft::CreateStorageUnit
    ODDraft::AcquireStorageUnit

    ODStorageUnitCursor

    ODStorageUnit::CreateCursor

    ODStorageUnitRefIterator

    ODStorageUnit::CreateRefIterator
    ODStorageUnitView::CreateStorageUnitRefIterator

    ODStorageUnitView

    ODStorageUnit::CreateView

    ODTransform

    ODTransform::Copy
    ODTransform::CopyFrom
    ODTransform::NewTransform
    ODFrame::CreateTransform
    ODFacet::CreateTransform

    ODTypeList

    ODStorageSystem::CreateTypeList

    ODTypeListIterator

    ODTypeList::CreateTypeListIterator

    ODOValueIterator

    ODOValueNameSpace::CreateIterator

    ODWindow

    ODWindowState::RegisterWindow
    ODWindowState::RegisterWindowForFrame

    ODWindowIterator

    ODWindowState::CreateWindowIterator

### Reference-Counted Objects

The use of reference-counted objects is part of the OpenDoc memory management scheme. Reference-counted objects maintain a count of the current number of references to them; that is, they are shared objects that are aware of how many other objects are making use of them at any one time.

During an OpenDoc session, many objects are created. Because there can be a very complex relationship among objects, it might be difficult for a part or for OpenDoc to determine when it is safe to delete an object from memory.

Reference-counting is a way to determine when a run-time object can be deleted, so that valuable memory space can be reclaimed.

A reference count is 0 or a positive integer. A value greater than 0 means that at least one reference to the object currently exists, and thus the object must not be removed from memory. All descendants of the class ODRefCntObject and any of its subclasses (including frames, links, link sources, and parts) are reference-counted.

Each reference-counted object is created through a call to its factory method, the method (usually in another class) responsible for creating that object and initializing its reference count. For example, a draft object is created by calling the CreateDraft or AcquireDraft method of a document object. Likewise, a frame object is created by calling the CreateFrame or AcquireFrame method of a draft object. See Table 12 for a list of factory methods.

These are the reference-counted objects:

- ODContainer
- ODDocument
- ODDraft
- ODExtension
- ODFrame
- ODLink
- ODLinkSource
- ODMenuBar
- ODPart
- ODPersistentObject
- ODPopup (for OS/2 and Windows)
- ODRefCntObject
- ODSettingsExtension
- ODShape
- ODStorageUnit
- ODTransform
- ODWindow

When it is first created by its factory object, a reference-counted object has a reference count of 1. Thus, the frame object returned by a draft's CreateFrame method always has a reference count of 1, because that method always creates a new object. The frame object returned by a draft's AcquireFrame method, however, may have a reference count greater than 1, because that method may return a reference to a preexisting frame.

Calling the Release method of a reference-counted object decrements its reference count; calling its Acquire method increments its reference count. Calling the Release method of a reference-counted object when its reference count is 1 causes its reference count to be set to 0 and may result in the object being deleted from memory. It is an error to access an object whose reference count is 0.

Each reference-counted object stores its own reference count and returns it to callers of its GetRefCount method. When the object's reference count goes to 0, the object is responsible for ensuring that it is removed from memory, either by deleting itself or by notifying its factory object which will remove it from memory.

Whenever your part editor writes a reference to a reference-counted object into a data structure, it should increment that object's reference count by calling its Acquire method. When your part editor is finished working with that object, it should call the object's Release method.

Because shape and transform objects are reference-counted and are widely used, it is important to remember always to release them instead of deleting them. Any method call with which you acquire a shape or transform must be balanced by a subsequent call to Release.

    clipShape = facet->AcquireClipShape(ev, biasCanvas);
      . . .
    clipShape->Release(ev);
    clipShape = kODNULL;

Likewise, any method call that assigns a reference-counted object to another object increases its reference count. Therefore, you can immediately release your own reference to it.

    newShape = facet->CreateShape(ev);
     . . .
    facet->ChangeGeometry(ev, newShape, transform, biasCanvas);
    newShape->Release(ev);
    newShape = kODNULL;

#### Acquire Versus Get

Methods whose names begin with Acquire increment the reference counts of the objects they return; methods whose names begin with Get do not. Every call to ODDraft::AcquireFrame, for example, must be balanced with a call to ODFrame::Release. A call to Facet::GetCanvas, on the other hand, requires no corresponding call to decrement reference count.

As a reference-counted object, your part is responsible for implementing an override of the Release method and for calling the ReleasePart method of its draft object when your part's reference count goes to 0. Your part does not need to release all of its references or do any other shutting down or deallocation at that point; the ReleasePart method calls your part's destructor, which should take care of deallocation. However, your part could get rid of unneeded structures or services before calling ReleasePart. For example, a communications part editor may choose to close its driver as soon as its reference count reaches 0.

If your part has a reference count of 0, but calling your draft's ReleasePart method has not resulted in your part's destruction, the draft object can retrieve and reuse your part. In that case, any structures or services you deallocated when the reference count went to 0 must be reallocated. Your Acquire method can perform those tasks for the case in which the reference count goes from 0 to 1.

Your part is destroyed after its ReleaseAll method is called, regardless of its current reference count, when its draft closes. See "Closing Your Part" for more information.

#### Testing Objects for Equality

If you need to compare two existing OpenDoc objects for equality, don't simply compare their pointers. Instead, call the IsEqualTo method (defined in ODObject) of either object. IsEqualTo always gives the correct result, even in a distributed environment when comparing pointers may fail. However, be sure never to call the IsEqualTo method of a null object reference.

### Handling Byte Arrays and Other Parameters

Many parameters to OpenDoc methods consist of references to objects or to other data that needs special attention in terms of allocating and releasing the storage associated with it. This section discusses parameter handling for byte arrays, strings, and objects.

To make the OpenDoc programming interface CORBA-compliant and capable of distributed execution, OpenDoc requires you to use a certain format when passing method parameters that point to buffers containing variable-length data.

OpenDoc defines the ODByteArray structure as a sequence of octets (unsigned 8-bit values). It consists of a buffer size field, a data length field, and a pointer to the buffer associated with the structure. All variable-length data is passed to or from OpenDoc with byte arrays. For example, the storage-unit methods GetValue and SetValue use byte arrays for the data being passed.

The caller of a method that takes variable-length data must place the data in a buffer pointed to by a byte array; the receiver of the data then retrieves the data from the buffer and uses it. Both sender and receiver must understand the underlying type of the data. For example, if your part calls SetValue, your part passes a structure of type ODByteArray, but the method understands the implied type of the contents of the buffer (a storage-unit value).

If you are the caller of a method that uses a byte array as a parameter, follow these rules for allocating and releasing the array:

- You as caller are responsible for allocating and releasing the storage of the byte array structure itself. You can allocate the byte array either on the stack or in the heap.

- If the byte array is an in parameter, you as caller allocate the storage for the data buffer the byte array points to, and you also release that storage after the method returns and you no longer need the data. (If the method needs to retain the data in the data buffer, it makes a copy).

- If the byte array is an out parameter or a function result, the method allocates the storage for the data buffer to which the byte array points; you as caller release that storage when you no longer need it.

All data passed by means of a byte array must be self-contained; for example, it can't contain pointers to data outside of itself.

If you are the caller of a method that uses a parameter that is a string (type ODISOString or one its equivalents, such as ODValueType) or an OpenDoc object, similar rules apply:

- If the string or object is an in parameter, you are responsible for both allocating and releasing its storage.

- If the string or object is an out parameter or a function result, the method allocates the storage and you must release the string or object when you no longer need it.

### Lazy Instantiation

Your part does not necessarily have to maintain frame objects in memory at all times for all of its embedded frames and display frames. You may have many display frames or embedded frames, only a few of which are visible at any one time. In such a case, you might want to reduce memory use by creating frame objects only for those frames that are currently visible. Then, as the user scrolls through your part or resizes it, or brings other display frames of your part into view, you can create frame objects for frames that appear, and release frame objects from frames that disappear. This process, which could be called lazy instantiation, works like this:

- At initialization, your part can create frame objects for just the visible frames of its embedded parts, as described in "Storing and Retrieving Embedded Frames".

- As each additional frame becomes visible through scrolling, resizing, or removal of obscuring content, you create the frame object by calling your draft's AcquireFrame method. OpenDoc then calls the DisplayFrameConnected method of the part (either your part or the embedded part) displayed in the frame.

- As each previously visible embedded frame becomes invisible, you can simply leave it in memory, or you can call the frame's Release method.

- Maintain connections to your released frames by their storage-unit IDs. If a previously released frame becomes visible again, you can recreate it once again by again calling AcquireFrame. OpenDoc in turn calls the part's DisplayFrameConnected method once again, if necessary.

[ Top | Previous | Next | Contents | Index | Documentation Homepage ]