Object Cache: CreateIt/FreeIt Pattern

MtxVec maintains a pre-allocated object pool (cache) for TVec and TMtx objects. CreateIt/FreeIt borrow and return objects from this pool — they do not allocate/free memory.

Why use CreateIt/FreeIt:

  • Objects are pre-allocated at startup → near-zero allocation cost
  • Pool objects have pre-allocated memory → no heap allocation for small sizes
  • Essential for block processing loops where objects are created/destroyed rapidly
  • Used with TVec/TMtx (pool-managed types), not with Vector/Matrix (value types)

Basic pattern:

// C++ (no finally: free on the error path and on the normal path)
TVec* a = nullptr;
TVec* b = nullptr;
TVec* c = nullptr;
CreateIt(a, b, c);   // borrow 3 objects from pool
try
{
    a->Size(1000);
    b->Size(1000);
    a->RandUniform();
    c->Sin(a);
    c->Add(b);
}
catch (...)
{
    FreeIt(a, b, c);   // return to pool, then let the exception propagate
    throw;
}
FreeIt(a, b, c);       // return to pool (not freed from memory)

Rules:

  1. Always pair CreateIt with FreeIt in try/finally
  2. Never mix CreateIt objects with regular constructor objects
  3. CreateIt objects are for LOCAL variables only — do not store in fields
  4. FreeIt does not destroy the object — it returns it to the pool for reuse

C++ has no finally, so in C++ rule 1 means two FreeIt calls: one in a catch (...) block that rethrows and one after the try block, as in the example above. FreeIt sets the pointer to nullptr (rule 5). Vector and Matrix need neither: their destructors return the object to the pool on every path out of the scope, exceptions included.

When to use what:

ScenarioUseWhy
General codeVector / MatrixAutomatic lifetime, operator support
Block processingCreateIt/FreeIt with TVec/TMtxL1 cache discipline, fast pool reuse
Temporary in tight loopCreateIt/FreeItNo GC pressure, predictable lifetime
Fields / propertiesVector / MatrixAutomatic management, no manual free

In C++, Vector, Matrix, VectorInt and MatrixInt use this object cache, as in Delphi — the value type borrows an object from the pool on first use, and its destructor returns it. new TVec() creates an object outside the pool; free it with delete.

Pool monitoring:

// Check for leaks — should be 0 after all FreeIt calls
TMtxVecPoolItem* pool = Controller->Pool[Controller->GetPoolIndex()];
int vecLeaks = pool->Vec->GetCacheUsedCount();
int mtxLeaks = pool->Mtx->GetCacheUsedCount();

In C++ pooling is not tied to a compiler switch: MTXVEC_RANGE_CHECKING adds the element-accessor checks and leaves the cache on. To turn CreateIt/FreeIt into real heap allocations that a leak checker can see, empty the cache at startup with Controller->SetVecCacheSize(0, 0) and Controller->SetMtxCacheSize(0, 0).