You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
VLA move construction with unequal allocators should preserve source capacity #211
Change allocator-extended move construction with unequal allocators to empty the source while preserving its buffer and capacity. This should match the existing unequal-allocator move-assignment behaviour.
The distinction should be whether ownership of the source allocation transfers. When storage is transferred, the source necessarily loses its capacity. When elements are relocated into storage owned by another allocator, the source should retain its allocation for reuse. Callers that want to release it can explicitly call shrink_to_fit() after the successful move.
Both unequal-allocator branches of move_assign_from finish with rhs.resize(0, rhs_max_size), destroying the elements while retaining the source allocation:
The allocator-extended move constructor instead deallocates the source buffer. Change the constructor to retain it; keep the assignment behaviour.
Rationale
This is a resource-management policy decision, not a correctness bug.
Relocation between unequal allocators requires the source buffer and destination storage to coexist while the elements are transferred. For construction, if the source buffer occupies S bytes and the destination buffer needs D bytes, both policies reach S + D bytes of container storage during relocation. Deallocating the source after relocation cannot reduce that peak.
Releasing the source does reduce retained memory after the operation, making its arena available for later allocations. Retaining it instead permits source reuse without another allocation. Both are useful in embedded systems, so callers should be able to choose. A caller can explicitly release retained storage, but cannot undo automatic deallocation: reserving the old capacity again requires allocator work and may fail.
Callers that want reclamation can use the same sequence regardless of allocator equality:
Under the proposed successful-move contract, the source is already empty. CETL's empty-container shrink_to_fit() directly deallocates retained storage without allocating a replacement, and is a no-op when capacity is already zero. This release behaviour should be documented for CETL; std::vector::shrink_to_fit() is only a nonbinding request.
Proposed change
In allocator-extended move construction with unequal allocators, destroy the source elements only after destination construction succeeds, set the source size to zero, and retain its data pointer, capacity, and allocator. Keep the existing storage-transfer behaviour when allocators compare equal. Ensure the bool specialization resets the source's last_byte_bit_fill_ consistently.
Keep source capacity retention in both unequal-allocator move-assignment branches. Replace the TODO with a comment explaining the deliberate retention policy.
Document the successful-move contract: storage-transfer paths leave the source empty with zero capacity; unequal-allocator relocation paths leave the source empty with its original capacity. Document explicit shrink_to_fit() for callers wanting release. Do not extend these successful-move postconditions to failed operations.
Update move-construction tests in test_variable_length_array_move_capacity.cpp and add corresponding move-assignment coverage. Cover nonempty and empty-but-reserved sources, both assignment capacity branches, and ordinary elements and packed bool. Verify retained source allocation ownership and capacity, allocation-free source reuse within that capacity, and explicit release by shrink_to_fit(). Keep equal-allocator storage-transfer checks and verify shrinking an already zero-capacity source is harmless.
Separate destination-buffer policy and exception guarantees
Keep the existing unequal-allocator move-assignment policy of freeing an insufficient destination buffer before allocating its replacement. Unlike releasing the source after relocation, this avoids keeping the old destination buffer alive alongside the source and replacement buffers, reducing the additional peak storage required during replacement.
Document the resulting exception guarantees separately. In the reallocate branch, failure during replacement allocation or element construction leaves the destination valid but empty rather than unchanged. The fits-in-capacity branch can leave destination elements partially updated if element assignment throws. Throwing element moves may also modify source values. Source-capacity retention does not imply a strong exception guarantee.
The move_assign_alloc calls in the unequal-allocator assignment branches are always no-ops because POCMA is false. Their conditional wording can be corrected, or the calls removed, in the same change.
changed the title [-]VLA move assignment with unequal allocators should release the source's storage[/-][+]VLA move construction with unequal allocators should preserve source capacity[/+]on Oct 6, 2026
Summary
Change allocator-extended move construction with unequal allocators to empty the source while preserving its buffer and capacity. This should match the existing unequal-allocator move-assignment behaviour.
The distinction should be whether ownership of the source allocation transfers. When storage is transferred, the source necessarily loses its capacity. When elements are relocated into storage owned by another allocator, the source should retain its allocation for reuse. Callers that want to release it can explicitly call
shrink_to_fit()after the successful move.Current behaviour
capacity() == 0capacity() == 0capacity() == 0capacity() == 0capacity() == 0capacity()unchangedBoth unequal-allocator branches of
move_assign_fromfinish withrhs.resize(0, rhs_max_size), destroying the elements while retaining the source allocation:// TODO: should we release the rhs capacity too?The allocator-extended move constructor instead deallocates the source buffer. Change the constructor to retain it; keep the assignment behaviour.
Rationale
This is a resource-management policy decision, not a correctness bug.
Relocation between unequal allocators requires the source buffer and destination storage to coexist while the elements are transferred. For construction, if the source buffer occupies S bytes and the destination buffer needs D bytes, both policies reach S + D bytes of container storage during relocation. Deallocating the source after relocation cannot reduce that peak.
Releasing the source does reduce retained memory after the operation, making its arena available for later allocations. Retaining it instead permits source reuse without another allocation. Both are useful in embedded systems, so callers should be able to choose. A caller can explicitly release retained storage, but cannot undo automatic deallocation: reserving the old capacity again requires allocator work and may fail.
Callers that want reclamation can use the same sequence regardless of allocator equality:
Under the proposed successful-move contract, the source is already empty. CETL's empty-container
shrink_to_fit()directly deallocates retained storage without allocating a replacement, and is a no-op when capacity is already zero. This release behaviour should be documented for CETL;std::vector::shrink_to_fit()is only a nonbinding request.Proposed change
boolspecialization resets the source'slast_byte_bit_fill_consistently.shrink_to_fit()for callers wanting release. Do not extend these successful-move postconditions to failed operations.test_variable_length_array_move_capacity.cppand add corresponding move-assignment coverage. Cover nonempty and empty-but-reserved sources, both assignment capacity branches, and ordinary elements and packedbool. Verify retained source allocation ownership and capacity, allocation-free source reuse within that capacity, and explicit release byshrink_to_fit(). Keep equal-allocator storage-transfer checks and verify shrinking an already zero-capacity source is harmless.Separate destination-buffer policy and exception guarantees
Keep the existing unequal-allocator move-assignment policy of freeing an insufficient destination buffer before allocating its replacement. Unlike releasing the source after relocation, this avoids keeping the old destination buffer alive alongside the source and replacement buffers, reducing the additional peak storage required during replacement.
Document the resulting exception guarantees separately. In the reallocate branch, failure during replacement allocation or element construction leaves the destination valid but empty rather than unchanged. The fits-in-capacity branch can leave destination elements partially updated if element assignment throws. Throwing element moves may also modify source values. Source-capacity retention does not imply a strong exception guarantee.
The
move_assign_alloccalls in the unequal-allocator assignment branches are always no-ops because POCMA is false. Their conditional wording can be corrected, or the calls removed, in the same change.Related