Deprecation of Size and Resize Methods
In the master branch, VTK has deprecated the GetSize() and Resize() methods
of vtkAbstractArray, which is the superclass of vtkDataArray. The reason for
this is that the behavior of these methods, though documented, was not
what people expected from their names. And as a result, these methods were
often used incorrectly.
Calling Resize(nTuples), for example, can decrease NumberOfTuples but cannot increase NumberOfTuples. Instead of increasing NumberOfTuples, it reserves extra slots for future growth of the array, similar to the C++ std::vector::reserve(n) method.
The array GetSize() method is likewise very confusing. Instead of returning the number of elements like std::vector::size(), it returns the reserved capacity of the array like std::vector::capacity(). This is particularly unexpected when a VTK array is wrapped in Python, since it causes array.size for a VTK array to have a different meaning from array.size for a numpy array.
A further point of confusion is that Resize() uses units of tuples, while GetSize() uses units of values. So even though they both refer to array capacity, they cannot be directly compared.
So what should you do if you need to resize an array? Use the method whose name is the best match for your intended action. If you only wish to change the capacity, use the new ReserveTuples() or ReserveValues() methods.
SetNumberOfTuples(n); // see below for changed behavior!
SetNumberOfValues(n);
ReserveTuples(n); // increase tuple capacity without changing NumberOfTuples
ReserveValues(n); // increase value capacity without changing NumberOfValues
As of VTK 9.7, and the master branch, SetNumberOfTuples(n) will be the most typical way to resize a data array. But be warned that in VTK 9.6 and earlier, if SetNumberOfTuples(n) was used to increase the size of an array, the previous data could be lost by memory reallocation. Only for VTK 9.7 and onwards is SetNumberOfTuples(n) guaranteed to preserve the data. To ensure compatibility with older versions of VTK, use array->SetNumberOfValues(n * array->GetNumberOfComponents()) since SetNumberOfValues() preserves data for both old and new versions of VTK.
This is an important point, so it’s worth repeating: until now, SetNumberOfValues() always preserved data but SetNumberOfTuples() did not. It’s only since this recent set of changes that they both preserve data.
New Reserve and Capacity Methods
Instead of GetSize() to get the capacity of an array (which might be larger than the array’s ‘size’), the new GetCapacity() method should be used.
Likewise, instead of Resize(n) to increase the capacity of an array, the new ReserveValues(n) and ReserveTuples(n) methods should be used. These new names make the intent explicit, and they will be familiar to people who use std::vector.
The Reserve methods are used to increase capacity, but not to reduce capacity. To reduce capacity, use the pre-existing Squeeze() method to shrink the memory allocation to fit the size of the array. To reduce the array capacity to below the current size, you must first reduce the size with SetNumberOfValues() or SetNumberOfTuples() before calling Squeeze().
Deprecation of Allocate Method
With the addition of ReserveTuples() and ReserveValues(), there is no longer any need for the array Allocate() method:
int Allocate(vtkIdType numValues, vtkIdType ext=1000);
There were a few problems with the Allocate() method. The second parameter did nothing, even though lots of old code in VTK used this parameter (to absolutely no effect). The parameters take units of values, not tuples, so one would often pass numberOfTuples * numberOfComponents as the first parameter.
In addition to the issues with its parameters, it also had some unexpected behaviors. It would not always do a fresh allocation, and would instead re-use the array’s current allocation if the current allocation was large enough. The names of the new methods ReserveValues() and ReserveTuples() make this re-use more explicit. Also, calling Allocate(0) had the special behavior of freeing the memory, which can be done more explicitly by calling the array’s Initialize() method.
In summary, instead of calling array->Allocate(), one should call:
SetNumberOfValues()/Tuples()if the goal is to set the array size.ReserveValues()/Tuples()if the goal is to set the array capacity.Initialize()if the goal is to free the memory.
Points and IdList
The Resize() and Allocate() methods of vtkPoints and vtkIdList are likewise deprecated because they had the same issues as the array methods. The new vtkPoints::Reserve() and vtkIdList::Reserve() methods can be used to allocate capacity or adjust capacity, while the existing SetNumberOfPoints() and SetNumberOfIds() methods can be used to adjust the size.
My Own Thoughts
I’m usually a stickler for backwards-compatibility in VTK, but I’ve found (and fixed) many VTK bugs caused by incorrect use of the array GetSize() and Resize() methods. I’ve seen enough bugs to convince me that these methods are unsafe, as are the Resize() methods for vtkPoints and vtkIdList. The array Allocate() isn’t as dangerous, so I have mixed feelings about deprecating it.