C++ Logo

std-discussion

Advanced search

Re: Size of heap allocated array

From: Thiago Macieira <thiago_at_[hidden]>
Date: Tue, 14 Apr 2026 09:41:45 -0700
On Tuesday, 14 April 2026 02:42:06 Pacific Daylight Time Marcin Jaczewski via
Std-Discussion wrote:
> Another case is recent `std-big-int` discursion on proposal mailing
> list and its reference implantation:
> https://github.com/eisenwave/std-big-int

For std::big_int, because the underlying type is likely to be a primitive,
there will be no size cookie controlled by C++ in the first place.

Most malloc() implementations remember the size of their blocks, so you could
use that (msize(), malloc_usable_size(), etc.). But that's really QoI and
might not be worth the out-of-line function call: just realloc() and be done
with it.

> where we have members like:
> ```
> std::uint32_t m_capacity; //
> 0 = static storage, >0 = heap capacity
> std::uint32_t m_size_and_sign; //
> bit 31 = sign, bits 0-30 = limb count
> data_type m_storage;
> BEMAN_BIG_INT_NO_UNIQUE_ADDRESS allocator_type m_alloc;
> ```

The way I'd design this -- the way I *have* designed such things -- is to move
the capacity and other stuff into the heap-allocated portion, keeping the type
itself as small as possible: two or three pointer widths.

The Qt array-type classes (QList/QVector, QByteArray and QString) all have the
same layout, provided by QArrayDataPointer:

private:
    typedef QTypedArrayData<T> Data;
    Data *d;
    T *ptr;
    qsizetype size;

We keep the capacity and reference count inside of the control block pointed
by d. For a statically-allocated container of those types (QByteArrayLiteral,
QStringLiteral, kind of Q_ARRAY_LITERAL too), all we need is to make that
control block d = nullptr.

We have a single heap allocation too: when we allocate memory, the d and ptr
pointers are dependent (ptr is usually just d + 1). This has the extra
advantage that ptr is a multiple of 16, reducing cacheline splits for SIMD
operatoins.

If we needed to compress things, we have a free bit in the size's MSB (heap
objects can't be bigger than PTRDIFF_MAX anyway) and at least two bits in the
d pointer's LSB.

We currently don't have SSO and this layout would not work for big endian, as
the free bits are only at the ends in little endian architectures, nor is ptr
at one end for libstdc++-like SSO. We also figured 10 characters is too few for
a worthwhile SSO. Assuming we don't add it in Qt 7, I'll probably move the
members around so ptr comes first and thus ptr & size are always in the same
cacheline, also matching the order in QStringView.
-- 
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
  Principal Engineer - Intel Data Center - Platform & Sys. Eng.

Received on 2026-04-14 16:41:53