Array Internals

How C# arrays and collections map to std::vector and related types.

The Core Mapping

C# T[] (fixed-size, reference type, GC-managed) maps to std::vector<T> (dynamic-size, value type by default, RAII-managed). This is the primary array type in sharp-runtime.

PropertyC# T[]sharp-runtime std::vector<T>
Type categoryReference typeValue type (copyable)
SizeFixed after creationDynamic; can grow/shrink
MemoryGC-managed heapRAII (freed when vector destroyed)
NullCan be nullCannot be null (empty vector by convention)
Lengtharr.Lengthvec.size()
Indexarr[i]vec[i] (same)
Bounds checkAlways (throws IndexOutOfRangeException)vec.at(i) throws; vec[i] does not

System::Array Role

System::Array provides static template methods for operating on std::vector<T>. It has a deleted constructor — you cannot create an instance. It acts as a namespace for algorithm helpers: Sort, Copy, Resize, IndexOf, Reverse, Clear.

include/System/Array.hpp

List<T> vs std::vector<T>

System::Collections::Generic::List<T> wraps std::vector<T> and provides a richer API (Add, Remove, Contains, Find, ForEach, etc.) along with the IList<T> interface. Choose between them:

List<T> exposes ToVector() to extract the underlying std::vector.

Immutable Collections

Immutable collections in System::Collections::Immutable are backed by shared_ptr<const std::container<T>>. This gives them value-copy semantics with shared underlying storage — cheap to copy but they cannot be modified after creation.

auto arr = System::Collections::Immutable::ImmutableArray<int>::Create({1, 2, 3});
// arr is backed by shared_ptr<const std::vector<int>>
auto arr2 = arr; // cheap copy (increments refcount)
// arr2[0] is still 1

Ownership and Passing Arrays

Because std::vector<T> is a value type, passing it by value copies all elements. Pass by reference (const std::vector<T>&) for read-only access, or by (std::vector<T>&) for mutable access.

// Pass by const ref (no copy)
void printAll(const std::vector<int>& numbers) {
    for (int n : numbers) std::cout << n << " ";
}

// Mutable ref (modifies caller's vector)
void addOne(std::vector<int>& numbers) {
    for (int& n : numbers) n++;
}

// Pass by value (caller keeps original)
std::vector<int> sorted = sortCopy(numbers); // makes a copy
C# array reference semantics
In C#, assigning an array variable copies the reference, not the data. In sharp-runtime, assigning a std::vector variable copies all the data. To get reference semantics, use std::shared_ptr<std::vector<T>>.

Bounds Checking

C# always bounds-checks array access and throws IndexOutOfRangeException. In C++:

For ported code that relies on proper bounds exceptions, use vec.at(i).

Multi-dimensional Arrays

C# multi-dimensional arrays (T[,] and T[][]) have no direct equivalent. Use nested vectors for jagged arrays or flatten to 1D for rectangular arrays:

// C# int[,] grid = new int[rows, cols]
std::vector<int> grid(rows * cols, 0);
// access: grid[row * cols + col]

// C# int[][] jagged
std::vector<std::vector<int>> jagged(rows);