Difference between revisions of "VTK/Tutorials/SmartPointers"

From KitwarePublic
< VTK‎ | Tutorials
Jump to navigationJump to search
Line 40: Line 40:
 
=== Returning a Smart Pointer ===
 
=== Returning a Smart Pointer ===
 
'''Correct'''
 
'''Correct'''
 +
 
You should define a function like this:
 
You should define a function like this:
 
<source lang="cpp">
 
<source lang="cpp">
Line 57: Line 58:
  
 
'''Incorrect'''
 
'''Incorrect'''
 +
 
<source lang="cpp">
 
<source lang="cpp">
 
vtkPolyData* MyFunction()
 
vtkPolyData* MyFunction()

Revision as of 10:40, 5 January 2010

Idea

The idea behind smart pointers is reference counting. If the object goes out of scope and it is not being used anywhere else, it will be deleted automatically. This is an important part of writing exception-safe code. Pretty 'smart', eh?

Usage

Creating an Object with a Smart Pointer

One way to create a VTK object is

vtkObject* MyObject = vtkObject::New();

This method, however, can (and likely will) lead to memory management issues at some point or another. You must manually delete the object

MyObject->Delete();

or you will have a memory leak. VTK's solution to this ever-annoying problem is the smart pointer. To use it, you must

#include <vtkSmartPointer.h>

Then you can create an object as follows:

vtkSmartPointer<vtkObject> MyObject = vtkSmartPointer<vtkObject>::New();

Getting an Object with a Smart Pointer

When not allocating memory for an object, you can still use smart pointers. Take this simple example:

vtkSmartPointer<vtkXMLPolyDataReader> Reader = vtkSmartPointer<vtkXMLPolyDataReader>::New();
vtkPolyData* pd = Reader->GetOutput();

vs

vtkSmartPointer<vtkPolyData> pd = Reader->GetOutput();

In the first case, when the reader object goes out of scope, the data is deleted. In the second case, by using a smart pointer we have incremented the data's reference count by 1, so the data will not be deleted until the reader AND the polydata object go out of scope.

Returning a Smart Pointer

Correct

You should define a function like this:

vtkSmartPointer<vtkPolyData> MyFunction()
{
  vtkSmartPointer<vtkPolyData> myObject = vtkSmartPointer<vtkPolyData>::New();
  return myObject;
}

And call the function using:

vtkSmartPointer<vtkPolyData> MyPolydata = MyFunction();

The smart pointer in the function is copied to the smart pointer in the caller, so the reference count remains unchanged and the associated object is not deleted.

Incorrect

vtkPolyData* MyFunction()
{
  vtkSmartPointer<vtkPolyData> MyObject = vtkSmartPointer<vtkPolyData>::New();
  return MyObject;
}

vtkPolyData* MyPolydata = MyFunction();

In this case, the smart pointer is converted to a raw pointer before being returned to the caller. As the function exits, the smart pointer's reference count goes to zero and the actual object is deleted, leaving the raw pointer dangling, pointing at freed memory.

Putting an Existing Object into a Smart Pointer

Using Smart Pointers as Class Member Variables

You should NOT (why?) use smart pointers for VTK class member variables.

Pitfalls

  • If you create an object and then change where it is pointing, the reference count will be incorrect. e.g.
vtkSmartPointer<vtkPolyData> Polydata = vtkSmartPointer<vtkPolyData>::New();
Polydata = Reader->GetOutput();

In this case, memory is allocated for Polydata, but then we change Polydata to point to the output of Reader rather than the memory we just allocated. Instead, we should have done simply:

vtkPolyData* Polydata = Reader->GetOutput();

It was not necessary to use a smart pointer because we did not actually create any new objects.

Example

Here is an example of equivalent operations with and without smart pointers:

SmartPointers.cpp

#include <vtkFloatArray.h>
#include <vtkSmartPointer.h>

void WithSmartPointers();
void WithoutSmartPointers();

int main(int argc, char *argv[])
{
  WithSmartPointers();
  WithoutSmartPointers();
	
  return 0;
}

void WithSmartPointers()
{
  vtkSmartPointer<vtkFloatArray> Distances = vtkSmartPointer<vtkFloatArray>::New();
}

void WithoutSmartPointers()
{
  vtkFloatArray* Distances = vtkFloatArray::New();
  Distances->Delete();
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.6)

PROJECT(SmartPointers)

FIND_PACKAGE(VTK REQUIRED)
INCLUDE(${VTK_USE_FILE})

ADD_EXECUTABLE(SmartPointers SmartPointers.cpp)
TARGET_LINK_LIBRARIES(SmartPointers vtkHybrid)