PathEngine home previous: Passing Arraysnext: Working with the TestBed
Contents, Programmers Guide, Applying the SDK, Ownership and Lifetimes

Ownership and Lifetimes

Reference counts

PathEngine interface object lifetimes are managed through a reference counting mechanism.

Every time you obtain a pointer to an interface object through the API, a reference count associated with that object is incremented internally by PathEngine.

When you no longer need to use the object, you directly or indirectly call the object's release() method (see for example iShape::release()), which decrements this reference count.

(The easiest way to do this is just to call the custom operator delete associated with the object, which calls on to the object's release() method. But it's good to be aware that this is actually just releasing one reference to the object, and doesn't actually force immediate object destruction.)

The object is then only actually deleted when the reference count gets to zero.

Reference relationships between API objects

Interface objects that need to refer to one another also use the same reference counting mechanism, and interface objects will therefore keep other interface objects 'alive' as necessary.

The ownership relationships between PathEngine interface objects form a directed acyclic graph, as follows.


Reference relationships between PathEngine interface objects.

Note that iCollisionContext and iObstacleSet may each reference multiple 'contained' objects. (iCollisionContext references zero or more iObstacleSets. iObstacleSet references zero or more iAgents.)

iContentProcessing3D and iTestBed are 'special' interfaces, but conceptually both reference a root iPathEngine object nevertheless.

Asserting that an object will de destroyed

Sometimes you want to be sure that the object is actually destroyed at a certain point in your code. (Because you want to reuse the memory used by the object, for example, or because you want to ensure that any cleanup costs are only incurred at certain times.)

What you can do here is to assert that nothing else is holding a reference to a pointer, before your call to release, as follows:

void ReleaseMesh_AssertActuallyDestroyed(iMesh* mesh)
{
    assert(!mesh->hasRefs());
    delete mesh; // (calls on to release)
}

The idea is that, if some other part of your code is holding on to an API object pointer that directly or indirectly references the mesh, you want to know about this, as opposed to just ignoring the references and invalidating the API object (potentially leading to a crash later on).

And then with this approach you effectively get the advantages of deterministic resource management together with the advantages of safe pointer management.

Using C++ smart pointer types with API object pointers

Because each API object class includes that custom delete operator, you can wrap API object pointers with C++ smart pointers (such as std::unique_ptr or std::shared_ptr) in exactly the same way as you would wrap pointers to objects allocated directly in the client application.

{
    int32_t agentRadius = 80;
    int32_t array[] =
    {
		    -agentRadius, -agentRadius,
		    -agentRadius, agentRadius,
		    agentRadius, agentRadius,
		    agentRadius, -agentRadius,
	  };
    unique_ptr<iShape> shape(pathEngine.newShape(array, sizeof(array) / sizeof(*array)));
    
    //.... do stuff with the shape
    
    //.... and the shape will then be released at the end of the scope
}

When the smart pointer object goes out of scope, the API object gets released. And when all smart pointers to an object (and to other, referencing, API objects) go out of scope, the object will be cleaned up.


Documentation for PathEngine release 6.00 - Copyright © 2002-2016 PathEnginenext: Working with the TestBed