[vtkusers] vtkImageAlgorithm output to preallocated buffer

David Gobbi david.gobbi at gmail.com
Sun Jan 22 13:33:49 EST 2017


On Sun, Jan 22, 2017 at 10:15 AM, Alessandro Volz <alessandro.volz at gmail.com
> wrote:

> Thanks David,
>
> So yes, I got there this way:
>     reslice->GetOutput()->GetPointData()->SetScalars(vtkSmartPointer<
> vtkFloatArray>::New());
>     reslice->GetOutput()->GetPointData()->GetScalars()->SetVoidArray
> (myBufferPtr, myBufferBytesLen, 1);
>
> It works fine, but could you explain why in vtkImageData::AllocateScalars we
> have:
>
>   if (scalars && scalars->GetDataType() == dataType
>       && scalars->GetReferenceCount() == 1)
>
> Why does it matter, the ReferenceCount be equal to 1 ?
>

I didn't know that check was there, but it is checking the reference count
to see if it holds the only reference to data array.  If it does, then it
simply reallocates the array that it has, otherwise it creates a new array.

Your code is creating a loose reference here:


reslice->GetOutput()->GetPointData()->SetScalars(vtkSmartPointer<vtkFloatArray>::New());

The SetScalars() method does not take a smart pointer, so the smart pointer
is being converted into a regular pointer.  The result is exactly the same
as if you called vtkFloatArray::New().

In VTK, you should only call vtkSmartPointer<vtkFloatArray>::New() if you
are assigning the result to a smart pointer.  Otherwise it's a memory
leak.  This is why most smart pointer like std::shared_ptr don't have a
typecast operator to allow them to devolve into regular pointers.  For VTK,
it was decided that the convenience of having a typecast operator was worth
the risk of memory leaks, since we have nightly testing to check for leaks.

To avoid the leak and fix the reference count,

    vtkSmartPointer<vtkFloatArray> scalars =
vtkSmartPointer<vtkFloatArray>::New();
    scalars->SetVoidArray(myBufferPointer, myBufferLen, 1);
    reslice->GetOutput()->GetPointData()->SetScalars(scalars);

And of course you'll have to make sure the smart pointer goes out of scope
before you call Update() on reslice.  To be absolutely sure the reference
count will be one when AllocateScalars is called, do this:

    vtkFloatArray *scalars = vtkFloatArray::New();
    scalars->SetVoidArray(myBufferPointer, myBufferLen, 1);
    reslice->GetOutput()->GetPointData()->SetScalars(scalars);
    scalars->Delete();

One further item of importance is that the "size" for SetVoidArray() is the
number of elements, not the number of bytes.  That's something that has
confused me in the past, and the documentation is not at all clear on that
point.

 - David
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/vtkusers/attachments/20170122/4bfbb58b/attachment.html>


More information about the vtkusers mailing list