Vuo  0.3
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Groups Pages

When a node allocates data on the heap (for example, with malloc) and sends it through an output port, the data travels to other nodes. The other nodes can hold onto that data for any amount of time. There's no guarantee of which node will be the last to use the data. Who is responsible for deallocating that data?

The answer is that the Vuo runtime is responsible for deallocating the data – but port type and node class definitions are responsible for informing the Vuo runtime about the data.

The Vuo runtime uses reference counting to keep track of heap-allocated memory and deallocate it when all nodes are finished using it. The Vuo API for node classes and port types provides three functions for reference counting:

To make the reference-counting system easier for you to use, the Vuo compiler automatically inserts many of the necessary calls to vuoRegister, vuoRetain, and vuoRelease. If you're implementing a stateless node class, you never need to call these functions. If you're implementing a stateful node class or a port type, read on to learn when to call these functions.

Defining a heap-allocated port type

If you define a port type that's a pointer to heap-allocated data, the typeInitWithString function is responsible for registering that data. For example:

typedef char * VuoString;
VuoString typeInitWithString(const char *initializer)
{
VuoString s = ...;
vuoRegister(s, free);
return s;
}

If your port type is a container for heap-allocated elements, then the type definition is responsible for registering each element that's allocated, retaining each element that's added, and releasing each element that's removed. For example:

typedef struct {
VuoString first;
VuoString second;
} PairOfStrings;
PairOfStrings typeInitWithString(const char *initializer)
{
PairOfStrings pair;
pair.first = ...;
pair.second = ...;
return pair;
}
void PairOfStrings_replaceFirst(PairOfStrings pair, VuoString newFirst)
{
vuoRetain(newFirst, free);
vuoRelease(pair.first);
pair.first = newFirst;
}

Using heap-allocated node instance data

If you define a stateful node class, and the node instance data is a pointer to heap-allocated data, the node class is responsible for calling vuoRegister on each instance of the type that's allocated. For example:

typedef int * ArrayOfIntegers;
ArrayOfIntegers nodeInstanceInit()
{
ArrayOfIntegers array = (ArrayOfIntegers)malloc(...);
vuoRegister(array);
return array;
}

If the node instance data is a container for heap-allocated elements, then the node class is responsible for registering each element that's allocated, retaining each element that's added, and releasing each element that's removed. For example:

typedef VuoString * ArrayOfStrings;
ArrayOfStrings nodeInstanceInit()
{
...
}
VuoInstanceData(ArrayOfStrings) array,
VuoInputData(VuoString) newString
) {
int i = ...;
VuoString oldString = array[i];
vuoRetain(newString);
vuoRelease(oldString);
array[i] = newString;
}
VuoInstanceData(ArrayOfStrings) array
) {
int elementCount = ...;
for (int i = 0; i < elementCount; ++i)
vuoRelease(array[i]);
}