Work with Arrays and Spans
Separate owned vectors from borrowed contiguous views before translating array operations.
Goal and component
Own a sequence, take a checked subrange, mutate through the view, and copy overlapping elements safely. All types in this tutorial belong to Core.Base.
Own with vector, borrow with Span
#include <System/Array.hpp>
#include <System/Span.hpp>
#include <vector>
std::vector<int> values{1, 2, 3, 4, 5};
System::Span<int> all(values);
auto middle = all.Slice(1, 3);
middle.Fill(9);
// values is now {1, 9, 9, 9, 5}
The vector owns. The span stores only data() and an element length. Its indexing and slicing are checked, but it cannot keep the vector alive.
Copy overlapping ranges
System::Span<int> source(values.data(), 4);
System::Span<int> destination(values.data() + 1, 4);
source.CopyTo(destination);
// CopyTo chooses an overlap-safe direction.
Do not replace this with memcpy. Overlap requires memmove-like direction, and non-trivial elements require assignment rather than object-representation copying.
Use Array algorithms on owned storage
System::Array::Sort(values);
const auto index = System::Array::IndexOf(values, 9);
System::Array::Reverse(values, 0, 3);
System::Array is a static algorithm class, not a base object. Its vector overloads validate signed ranges. Floating default sort uses the project’s explicit NaN-first policy.
Know what invalidates the view
auto view = System::Span<int>(values);
values.push_back(6); // may reallocate
// Do not use view after a potentially relocating operation.
Reserve is not a permanent lifetime contract: any later operation that exceeds capacity can relocate. Destruction always invalidates. Erase/insert can change which elements an offset describes even when the buffer does not move.
Read-only means through this alias
ReadOnlySpan<T> prevents mutation through the view. Another alias can still mutate the same storage. For a retained immutable value, own a const value or enforce immutability at the owner rather than relying on one read-only borrow.
Do not use current Memory as an async owner
Memory<T> and ReadOnlyMemory<T> borrow a vector in this implementation. Pin() returns its current native pointer but does not retain or immobilize the vector. Cross an async boundary with an explicit owner plus offsets, not a borrowed view alone.
Verification checklist
- Empty, exact-end, negative, and oversized slices.
- Overlapping copy in both directions with non-trivial elements.
- Owner destruction and vector reallocation.
- Raw-pointer boundaries with explicit capacity proof.
- Multidimensional index multiplication overflow if using flattened storage.