Alias UniquePtr
UniquePtr
is a smart pointer that owns and manages object through a pointer and disposes of that object when the UniquePtr
goes out of scope.
UniquePtr
is alias to RcPtr
with immutable _ControlType
.
The object is destroyed and its memory deallocated when either of the following happens:
1. the managing UniquePtr
object is destroyed
2. the managing UniquePtr
object is assigned another pointer via various methods like opAssign
and store
.
The object is destroyed using delete-expression or a custom deleter that is supplied to UniquePtr
during construction.
A UniquePtr
may alternatively own no object, in which case it is called empty.
Template parameters:
_Type
type of managed object
_DestructorType
function pointer with attributes of destructor, to get attributes of destructor from type use DestructorType!T
. Destructor of type _Type
must be compatible with _DestructorType
_ControlType
represent type of counter, must by of type immutable ControlBlock
.
Example
static class Foo{
int i;
this(int i)pure nothrow @safe @nogc{
this .i = i;
}
}
static class Bar : Foo{
double d;
this(int i, double d)pure nothrow @safe @nogc{
super(i);
this .d = d;
}
}
static class Zee : Bar{
bool b;
this(int i, double d, bool b)pure nothrow @safe @nogc{
super(i, d);
this .b = b;
}
~this()nothrow @system{
}
}
import core .lifetime : move;
///simple:
{
UniquePtr!long a = UniquePtr!long .make(42);
UniquePtr!(const long) b = move(a);
assert(a == null);
assert(*b == 42);
assert(b .get == 42);
}
///polymorphism:
{
///create UniquePtr
UniquePtr!Foo foo = UniquePtr!Bar .make(42, 3.14);
UniquePtr!Zee zee = UniquePtr!Zee .make(42, 3.14, false);
///dynamic cast:
UniquePtr!Bar bar = dynCastMove!Bar(foo);
assert(foo == null);
assert(bar != null);
///this doesnt work because Foo destructor attributes are more restrictive then Zee's:
//UniquePtr!Foo x = move(zee);
///this does work:
UniquePtr!(Foo, DestructorType!(Foo, Zee)) x = move(zee);
assert(zee == null);
}
///multi threading:
{
///create SharedPtr with atomic ref counting
UniquePtr!(shared Foo) foo = UniquePtr!(shared Bar) .make(42, 3.14);
///this doesnt work:
//foo.get.i += 1;
import core .atomic : atomicFetchAdd;
atomicFetchAdd(foo .get .i, 1);
assert(foo .get .i == 43);
///creating `shared(UniquePtr)`:
shared UniquePtr!(shared Bar) bar = share(dynCastMove!Bar(foo));
///`shared(UniquePtr)` is lock free.
static assert(typeof(bar) .isLockFree == true);
///multi thread operations (`store`, `exchange`):
UniquePtr!(shared Bar) bar2 = bar .exchange(null);
}
///dynamic array:
{
import std .algorithm : all, equal;
UniquePtr!(long[]) a = UniquePtr!(long[]) .make(10, -1);
assert(a .length == 10);
assert(a .get .length == 10);
assert(a .get .all!(x => x == -1));
for(int i = 0; i < a .length; ++i){
a .get[i] = i;
}
assert(a .get[] == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
}
Example
//make UniquePtr object
static struct Foo{
int i;
this(int i)pure nothrow @safe @nogc{
this .i = i;
}
}
{
auto foo = UniquePtr!Foo .make(42);
auto foo2 = UniquePtr!Foo .make!Mallocator(42); //explicit stateless allocator
}
{
auto arr = UniquePtr!(long[]) .make(10); //dynamic array with length 10
assert(arr .length == 10);
}
Example
//alloc UniquePtr object
import std .experimental .allocator : make, dispose, allocatorObject;
auto allocator = allocatorObject(Mallocator .instance);
{
auto x = UniquePtr!(long) .alloc(allocator, 42);
}
{
auto arr = UniquePtr!(long[]) .alloc(allocator, 10); //dynamic array with length 10
assert(arr .length == 10);
}
Example
{
auto x = UniquePtr!(shared long) .make(123);
import core .lifetime : move;
shared s = share(x .move);
assert(x == null);
auto y = s .exchange(null);
assert(*y == 123);
}
{
auto x = UniquePtr!(long) .make(123);
///error `shared UniquePtr` need shared `ControlType` and shared `ElementType`.
//shared s = share(x);
}