unique<T> ownership
unique<T> provides exclusive ownership of at most one heap allocation. It cannot be copied, transfers explicitly with move, and deterministically destroys and frees its allocation when the live owner dies.
Create an owner
unique<Resource> resource = new Resource(42);
unique<int> number = new int(42);
unique<int[]> values = new int[100];
A matching fresh heap new allocation may enter unique ownership through direct initialization or assignment. This adoption does not allocate a second object or add a control block. An existing owner is transferred to another unique<T> with move, and default-initialized ownership storage may be empty.
Raw pointers and raw array variables cannot be adopted into unique<T> ownership. That restriction prevents two values from believing they own the same allocation.
Access the owned value
resource->Reset();
resource->Count = 1;
values[0] = 10;
int length = values.Length;
int rank = values.Rank;
int firstDimension = values.GetLength(0);
An object owner uses Xenon's pointer-style -> member and method access. An owner of an array supports normal indexing and array metadata. Primitive owners use dereference syntax, for example *number = 7. Every built-in primitive except void is supported; new T() zero-initializes it and new T(value) stores one matching initializer. Access reads or mutates the pointee; it does not transfer ownership.
A safe reference borrows the owned allocation, not the local handle. The usual one-mutable-or-many-readonly rule therefore applies to *owner and owner->Field, and direct owner access must respect an active borrow:
unique<int> value = new int();
int& first = *value;
int& second = *value; // error while first remains active
first = 10;
second = 20;
The borrow remains flow-sensitive and ends after its final use. Moving the owner preserves the allocation identity at the destination, and moving it while a reference still needs the pointee is rejected.
Transfer, do not copy
unique<Resource> first = new Resource();
unique<Resource> second = move first;
// Rejected: first no longer contains a live owner.
// first->Reset();
// Rejected: unique values are non-copyable.
// unique<Resource> third = second;
A successful move transfers the handle and its cleanup responsibility. The source becomes moved and is not destroyed. Reassigning the source from another fresh new expression makes it live again.
Move-assignment first evaluates and captures the incoming handle, destroys a live old destination, stores the handle, then disables cleanup at the source. Replacing an owner with a fresh allocation also destroys its previous allocation first.
A method that leaves a unique field of this moved changes caller-visible receiver state. A polymorphic implementation cannot introduce a persistent receiver move effect that is absent from the callable contract visible to the caller. See Callable move effects.
Automatic destruction
At scope exit and every control-flow exit, a live unique<T> runs the complete destructor logic for T and then deallocates through Xenon's allocator ABI. An empty default-initialized or moved owner performs no destruction.
For unique<T[]>, live elements are destroyed in reverse order before the backing allocation is freed. This is the same element-destruction behavior used by an explicit delete on a raw heap array.
Creating, transferring, overwriting, returning, or otherwise acquiring unique<T> is allowed only where the complete destructor of T is accessible. The check follows array elements, base structs, nested fields, and nested ownership fields, so a generated destructor cannot bypass a private user destructor. Primitive pointees need no user destructor.
free(owner) and delete(owner) are rejected. Automatic ownership destruction is the single release path. Use free for storage-only raw allocations and delete for typed raw heap objects or arrays.
Fields and generics
struct Holder<T>
{
public unique<T> Value;
}
struct List<T>
{
private unique<T[]> _items;
}
Box<unique<Resource>> nested;
Ownership types participate in generic substitution and nested type identity. A struct containing a unique field becomes non-copyable transitively, while whole-struct and field moves remain available. A field can be moved out when no aggregate on its path has a user-defined destructor.
Generic inference looks through the wrapper. Calling Consume(move value) for a parameter of type unique<T> infers T from the owner type, including when the wrapper occurs inside another generic struct. Structural template matching also substitutes template self recursively inside unique<Self>.
Directly nesting ownership wrappers, such as unique<shared<Resource>>, is rejected. Store an ownership wrapper in an ordinary container such as Box<unique<Resource>> instead.
A compiler-generated destructor does not count as a user destructor: it destroys each still-live ownership field exactly once and still permits safe partial moves.
Interop boundary
unique<T> is a Xenon ownership type whose representation is internal and is not part of the C ABI. Direct extern and export signatures containing it are rejected. Use raw pointers and an explicit ownership contract at a C boundary.