View source code
Display the source code in std/typecons.d from which this page was generated on github.
Report a bug
If you spot a problem with this page, click here to create a Bugzilla issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone.

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.

SafeRefCounted!(T,RefCountedAutoInitialize.no) safeRefCounted(T) (
  T val
);

Parameters

NameDescription
val The value to be reference counted

Returns

An initialized SafeRefCounted containing val.

See Also

refCounted C++'s make_shared

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.yes (the default option) is convenient but has the cost of a test whenever the payload is accessed. If autoInit == RefCountedAutoInitialize.no, user code must call either refCountedStore.isInitialized or refCountedStore.ensureInitialized before attempting to access the payload. Not doing so results in null pointer dereference.

If T.this() is annotated with @disable then autoInit must be RefCountedAutoInitialize.no in order to compile.

Constructors

NameDescription
this (args) Constructor that initializes the payload.

Properties

NameTypeDescription
refCountedPayload[get] TReturns a reference to the payload. If (autoInit == RefCountedAutoInitialize.yes), calls refCountedStore.ensureInitialized. Otherwise, just issues assert(refCountedStore.isInitialized). Used with alias refCountedPayload this;, so callers can just use the SafeRefCounted object as a T.
refCountedStore[get] inout(SafeRefCounted.RefCountedStore)Returns storage implementation struct.

Methods

NameDescription
opAssign (rhs) Assignment operators.

Inner structs

NameDescription
RefCountedStore SafeRefCounted storage implementation.

See Also

RefCounted

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

License

Boost License 1.0.