A Tour of VTK Pointer Classes

April 15, 2011

One way in which VTK’s API differs from that of other libraries is that all vtkObjectBase-derived classes must be allocated from the heap. This means that we tend to deal with raw pointers a lot more often than those developing code using other libraries and frameworks, such as the standard template library, Boost and Qt. This has led to the addition of several templated classes to make pointer management, along with allocation and deallocation, easier.

vtkNew
The newest addition to the set of pointer classes is vtkNew, which is designed to allocate and hold a VTK object. Due to the nature of VTK constructors (no arguments), it is a very simple class; on construction it allocates a new VTK object of the type specified, and on destruction it will call the Delete() method of the class.

vtkNew<vtkPoints> points;
points->SetDataTypeToDouble();

This class effectively maintains ownership of the object, provides a very compact way of allocating VTK objects, and assures that they will be deleted when the pointer goes out of scope in much the same way as stack allocated objects. The class is new in VTK 5.8.0. To pass the raw pointer to other classes it is necessary to use the GetPointer() method,

myObject->SetPoints(points.GetPointer());

This class can also be used as a member variable in classes where the class contains instances of other VTK classes that should be allocated on construction, and deallocated on destruction. It is not necessary to include the header of the class the vtkNew pointer will use in the header, just the implementation file containing the constructor definition.
If the member variable can be changed in the API of the class (for example through a Set…() method), vtkSmartPointer would be a better choice.

vtkSmartPointer
This is the oldest of the pointer classes, providing a container that holds a reference to a vtkObjectBase reference.
The vtkSmartPointer class is templated and derived from vtkSmartPointerBase. It adds automatic casting for objects held by its superclass. To allocate a new VTK object and store it in a vtkSmartPointer use

vtkSmartPointer<vtkPoints> points =
vtkSmartPointer<vtkPoints>::New();

Using the contained object works in much the same way as using vtkNew.

points->SetDataTypeToDouble();

This pointer class also allows implicit casts to the underlying pointer, and so to pass the instance to another class is a little simpler as it looks just like a normal pointer to the function, for example,

myObject->SetPoints(points);

The vtkSmartPointer class can also be used as a member variable. It is more suitable for the case where the class has API to set what the member variable is pointing to, while maintaining ownership of that class. On assignment, the smart pointer will increment the reference count of the object, and on destruction (or allocation of a different instance to the smart pointer) the reference count will be decremented.This can be especially helpful in the case of things such as input data, where the user of a class can set vtkImageData, for example, as the input, which is stored by the class in a member variable of type vtkSmartPointer<vtkImageData> and can then be used later. If the image that was passed in is later deleted the smart pointer assures that the reference count is still non-zero and the object remains valid. It can cause issues with reference loops in some cases, and there are also situations where it is more helpful to simply hold on to a pointer that will become null should the instance be deleted. The vtkWeakPointer class addresses these use cases.

vtkWeakPointer
The vtkWeakPointer class is the third of our pointer classes, providing a weak reference to a vtkObject. This means that assigning to the vtkWeakPointer does not increase the reference count of the instance. When the instance being pointed to is destroyed, the vtkWeakPointer being held on to gets set to null, avoiding issues with dangling pointers. It is especially useful in cases where you need to hold on to a pointer for an instance, but there is no need to keep it around should it be deleted. This often makes it far easier to avoid any reference loops as well.

vtkTable *table = vtkTable::New();
vtkWeakPointer<vtkTable> weakTable = table;

The weakTable will remain valid until Delete() is called, so in the following code weakTable will never evaluate to true.

table->Delete();
if (weakTable)
{
// We’ll never get here, as table was deleted.
vtkIdType num = weakTable->GetNumberOfColumns();
}

This makes it very easy to check for null before doing anything with the pointer. It is again useful for member variables of classes, in the case where there is no need to maintain ownership of the instance being pointed to.
It should be noted that the above code is not thread safe.

Use of Classes
As mentioned previously, each of the pointer classes can be used for member variables in classes. They have different attributes, and so the intended API around the data being pointed to should be considered.

vtkNew: Strong ownership, where the class instantiates an object which it owns for the lifetime of the class.
The member cannot be changed in place (much like stack variables).

vtkSmartPointer: Ownership of the instance is maintained. The class may or may not instantiate the initial object
and the instance being pointed to can be changed.

vtkWeakPointer: Weak ownership, where the class does not instantiate an object. If the object instance is deleted, then the weak pointer is null, which avoids dangling pointers without ownership.

A simplified class definition might look like,

#include “vtkObject.h”
#include “vtkNew.h”
#include “vtkSmartPointer.h”
#include “vtkWeakPointer.h”
class vtkTable;
class vtkExample
{
static vtkExample * New();
void SetInputTable(vtkTable *table);
vtkTable * GetInputTable();
void SetColorTable(vtkTable *table);
vtkTable * GetColorTable();
vtkTable * GetTableCache();
protected:
vtkExample();
~vtkExample();
vtkNew<vtkTable> TableCache;
vtkSmartPointer<vtkTable> InputTable;
vtkWeakPointer<vtkTable> ColorTable;
};

The corresponding implementation file would contain,

#include “vtkExample.h”
#include “vtkObjectFactory.h”
#include “vtkTable.h”
vtkStandardNewMacro(vtkExample)
vtkExample::vtkExample()
{
this->InputTable =
vtkSmartPointer<vtkTable>::New();
}
vtkExample::~vtkExample() { }
void vtkExample::SetInputTable(vtkTable *table)
{
this->InputTable = table;
}
vtkTable * vtkExample::GetInputTable()
{
return this->InputTable.GetPointer();
}
void vtkExample::SetColorTable(vtkTable *table)
{
this->ColorTable = table;
}
vtkTable * vtkExample::GetColorTable()
{
return this->ColorTable.GetPointer();
}
vtkTable * vtkExample::GetTableCache()
{
return this->TableCache.GetPointer();
}

Note that there was no need to call Delete() on any of the member variables. The vtkNew class allocates the vtkTable on construction, and that instance cannot be replaced over the lifetime of the class instance. When the class is destructed, the vtkNew object calls delete on the table. Next, vtkSmartPointer allocates an initial instance of vtkTable, which can later be replaced using SetInputTable. Finally vtkWeakPointer may be set using SetColorTabl; if it is, it will point to that instance until it is destroyed.

Pointer Class Interaction
The pointer classes all work with each other. The vtkNew class is ideal for allocation of new objects in a very concise form. Since it just decrements the reference count when it goes out of scope, it works as expected when used with the other two pointer classes.

vtkNew<vtkTable> nTable; // Reference count of 1

vtkSmartPointer<vtkTable> spTable =
nTable.GetPointer();      //  Reference count of 2

vtkWeakPointer<vtkTable> wpTable =
nTable.GetPointer();    // Reference count of 2

Once the nTable and spTable objects go out of scope, the reference count would drop to zero, and the wpTable would be set to null. There is no assignment of objects to vtkNew, and so other pointers cannot be assigned to it. Both vtkSmartPointer and vtkWeakPointer have implicit casting to the pointer type of the class and define the equality operator between them, and so the GetPointer() call is not strictly necessary when converting between these two pointer types and raw pointers.

Conclusions
Each of the classes has online documentation, and each satisfies a specific need in VTK. They should make memory management in your classes and applications simpler if used correctly, reducing line counts and decreasing code complexity. They are also suitable for use in classes, and only their header needs to be included in the declaration file. The new vtkNew class is especially useful in things like tests and small sample applications where several classes must be allocated. The vtkSmartPointer and vtkWeakPointer complement one another where pointers must be held on to for later use.

 

Marcus Hanwell is an R&D engineer in the scientific visualization team at Kitware . He joined the company in October 2009, and has a background in open source, Physics and Chemistry. He spends most of his time working with Sandia on VTK, Titan and ParaView.

 

Leave a Reply