std.typecons.SafeRefCounted/safeRefCounted
- multiple declarations
Function safeRefCounted
Initializes a SafeRefCounted
with val
. The template parameter
T
of SafeRefCounted
is inferred from val
.
This function can be used to move non-copyable values to the heap.
It also disables the autoInit
option of SafeRefCounted
.
Parameters
Name | Description |
---|---|
val | The value to be reference counted |
Returns
An initialized SafeRefCounted
containing val
.
See Also
Example
static struct File
{
static size_t nDestroyed;
string name;
@disable this(this); // not copyable
~this() { name = null; ++nDestroyed; }
}
auto file = File("name");
writeln(file .name); // "name"
// file cannot be copied and has unique ownership
static assert(!__traits(compiles, {auto file2 = file;}));
writeln(File .nDestroyed); // 0
// make the file ref counted to share ownership
// Note:
// We write a compound statement (brace-delimited scope) in which all `SafeRefCounted!File` handles are created and deleted.
// This allows us to see (after the scope) what happens after all handles have been destroyed.
{
// We move the content of `file` to a separate (and heap-allocated) `File` object,
// managed-and-accessed via one-or-multiple (initially: one) `SafeRefCounted!File` objects ("handles").
// This "moving":
// (1) invokes `file`'s destructor (=> `File.nDestroyed` is incremented from 0 to 1 and `file.name` becomes `null`);
// (2) overwrites `file` with `File.init` (=> `file.name` becomes `null`).
// It appears that writing `name = null;` in the destructor is redundant,
// but please note that (2) is only performed if `File` defines a destructor (or post-blit operator),
// and in the absence of the `nDestroyed` instrumentation there would have been no reason to define a destructor.
import std .algorithm .mutation : move;
auto rcFile = safeRefCounted(move(file));
writeln(rcFile .name); // "name"
writeln(File .nDestroyed); // 1
writeln(file .name); // null
// We create another `SafeRefCounted!File` handle to the same separate `File` object.
// While any of the handles is still alive, the `File` object is kept alive (=> `File.nDestroyed` is not modified).
auto rcFile2 = rcFile;
writeln(rcFile .refCountedStore .refCount); // 2
writeln(File .nDestroyed); // 1
}
// The separate `File` object is deleted when the last `SafeRefCounted!File` handle is destroyed
// (i.e. at the closing brace of the compound statement above, which destroys both handles: `rcFile` and `rcFile2`)
// (=> `File.nDestroyed` is incremented again, from 1 to 2):
writeln(File .nDestroyed); // 2
Struct SafeRefCounted
Defines a reference-counted object containing a T
value as
payload.
struct SafeRefCounted(T, RefCountedAutoInitialize autoInit = RefCountedAutoInitialize .yes)
if (!is(T == class) && !is(T == interface));
An instance of SafeRefCounted
is a reference to a structure,
which is referred to as the store, or storage implementation
struct in this documentation. The store contains a reference count
and the T
payload. SafeRefCounted
uses malloc
to allocate
the store. As instances of SafeRefCounted
are copied or go out of
scope, they will automatically increment or decrement the reference
count. When the reference count goes down to zero, SafeRefCounted
will call destroy
against the payload and call free
to
deallocate the store. If the T
payload contains any references
to GC-allocated memory, then SafeRefCounted
will add it to the GC memory
that is scanned for pointers, and remove it from GC scanning before
free
is called on the store.
One important consequence of destroy
is that it will call the
destructor of the T
payload. GC-managed references are not
guaranteed to be valid during a destructor call, but other members of
T
, such as file handles or pointers to malloc
memory, will
still be valid during the destructor call. This allows the T
to
deallocate or clean up any non-GC resources immediately after the
reference count has reached zero.
Without -preview=dip1000, SafeRefCounted
is unsafe and should be
used with care. No references to the payload should be escaped outside
the SafeRefCounted
object.
With -preview=dip1000, SafeRefCounted
is safe if it's payload is accessed only
with the borrow
function. Scope semantics can also prevent accidental
escaping of refCountedPayload
, but it's still up to the user to not destroy
the last counted reference while the payload is in use. Due to that,
refCountedPayload
remains accessible only in @system
code.
The autoInit
option makes the object ensure the store is
automatically initialized. Leaving autoInit ==
RefCountedAutoInitialize
(the default option) is convenient but
has the cost of a test whenever the payload is accessed. If autoInit == RefCountedAutoInitialize
, user code must call either
refCountedStore
or refCountedStore
before attempting to access the payload. Not doing so results in null
pointer dereference.
If T
is annotated with @disable
then autoInit
must be
RefCountedAutoInitialize
in order to compile.
Constructors
Name | Description |
---|---|
this
(args)
|
Constructor that initializes the payload. |
Properties
Name | Type | Description |
---|---|---|
refCountedPayload [get]
|
T | Returns a reference to the payload. If (autoInit ==
RefCountedAutoInitialize.yes), calls refCountedStore . Otherwise, just issues assert(refCountedStore . Used with alias
refCountedPayload this; , so callers can just use the SafeRefCounted
object as a T .
|
refCountedStore [get]
|
inout(SafeRefCounted | Returns storage implementation struct. |
Methods
Name | Description |
---|---|
opAssign
(rhs)
|
Assignment operators. |
Inner structs
Name | Description |
---|---|
RefCountedStore
|
SafeRefCounted storage implementation.
|
See Also
Example
// A pair of an `int` and a `size_t` - the latter being the
// reference count - will be dynamically allocated
auto rc1 = SafeRefCounted!int(5);
writeln(rc1); // 5
// No more allocation, add just one extra reference count
auto rc2 = rc1;
// Reference semantics
rc2 = 42;
writeln(rc1); // 42
// the pair will be freed when rc1 and rc2 go out of scope
Authors
Andrei Alexandrescu, Bartosz Milewski, Don Clugston, Shin Fujishiro, Kenji Hara