Kernel SDK Developer's Guide > Basic Operations > Working with Dynamic Arrays
Working with Dynamic Arrays

A dynamic array object is implemented by the OdArray template class. Dynamic arrays use the following concepts:

  • Logical Length or Size – The number of entries in the array. Initially it is zero.
  • Physical Length – The maximum logical length of the array before it automatically grows.
  • Grow Length – The number of entries by which the physical length will grow as required.

Size of the array can be increased and decreased. To avoid memory reallocation every time an element is added to the array:

  • Physical length can be set greater than the logical length (see reserve() method).
  • Extra data size is reserved when appending even one element (see nGrowBy parameter).

OdArray stores a reference to a buffer where array elements reside. The buffer can be referenced by more than one array and has a reference counter. For example, after assigning one array to another, both of them reference the same buffer and actual data is not copied. If an array is going to be modified at the beginning of each non-const function, the buffer's reference counter is checked, and if the buffer is referenced by more than one array, it is copied.

OdArray<double> arr1, arr2, arr3;
arr1.append(1.);
arr1.append(2.);
arr2 = arr1;
arr3 = arr1;
// Here all 3 arrays reference the same buffer

arr1.append(3.);
// Here arr2 and arr3 still reference the same buffer with 2 elements.
// And arr1 references new buffer - copy of the first buffer plus 3-rd element added.

Memory and object allocators (template parameter)

If an object's allocator is used, constructors and destructors of array elements are called when elements are appended, destroyed or moved during the buffer's reallocation.

A memory allocator does not call constructors and destructors. It helps to improve performance but is not suitable for all classes.

The Kernel API has typedefs for commonly used array types. For example:

/** \details
  This template class is a specialization of the OdArray class for OdGePoint3d objects.
*/
typedef OdArray<OdGePoint3d, OdMemoryAllocator<OdGePoint3d> > OdGePoint3dArray;

Performance tips

1. OdArray vs. static arrays. If you need data storage of known size and it is not large, OdArray is not the best choice because of overhead (extra code executed and memory allocations):

void polyline(OdGePoint3d* pPoints, int length);

void myLine(const OdGePoint3d& p1, const OdGePoint3d& p2)
{
  ...
  //Poor practice
  OdGePoint3dArray arPoints;
  arPoints.append(p1);
  arPoints.append(p2);
  polyline(arPoints.asArrayPtr(), arPoints.size();

  // Much better
  OdGePoint3d points[2];
  points[0] = pt1;
  points[1] = pt2;
  polyline(points, 2);
}

2. Use a memory allocator if suitable. It will prevent multiple calls to constructors and destructors.

3. If data size is known, use reserve() to allocate required memory at the very beginning. This will prevent multiple reallocations and data copying as the array grows.

OdGePoint3dArray arPts;
int nPointsToStore = rdInt();
arrPts.reserve(nPointToStore);
while (nPointToStore--)
{
  arrPts.append(rdPoint3d());
}

//Or even better - avoiding calls to append()
OdGePoint3dArray arPts;
int nPointsToStore = rdInt();
arrPts.resize(nPointToStore);
OdGePoint3d* pPts = arrPts.asArrayPtr();
while (nPointToStore--)
{
  *pPts++ = rdPoint3d();
}

4. Const methods usage is preferable. If a non-const method is called and the array buffer has more than 1 reference, the buffer will be copied:

void MyFunc(OdGePoint3dArray arPoints)
{
  OdGePoint3d* pPoints = arPoints.asArrayPtr(); // Here buffer will be copied because parameter is passed by value and buffer for sure has more than 1 reference
  for (int i = arPoints.size(); i > 0; i--)
    wrPoint3d(pPoints++);
}

Better:

void MyFunc(OdGePoint3dArray arPoints)
{
  const OdGePoint3d* pPoints = arPoints.asArrayPtr(); // Here buffer will not be copied because const method is used.
  for (int i = arPoints.size(); i > 0; i--)
    wrPoint3d(pPoints++);
}

For an array that is not expected to be modified, it is better to pass the array using a const reference. Using non-const functions will produce compilation errors.

void MyFunc(const OdGePoint3dArray& arPoints)
{
  // Compilation error
  OdGePoint3d* pPoints = arPoints.asArrayPtr();
  // OK
  const OdGePoint3d* pPoints = arPoints.asArrayPtr();
  for (int i = arPoints.size(); i > 0; i--)
    wrPoint3d(pPoints++);
}
Copyright © 2002 – 2022. Open Design Alliance. All rights reserved.