Class Subspace :: sus :: boxed :: Box
A heap allocated object.
A Box<T> holds ownership of an object of type T on the heap. When Box
is destroyed, or an rvalue-qualified method is called, the inner heap
object is freed.
Box is similar to std::unique_ptr with some differences,
and should be preferred when those differences will benefit you:
- Const correctness. A
const Boxtreats the inner object asconstand does not expose mutable access to it. - Never null. A
Boxalways holds a value until it is moved-from. It is constructed from a value, not a pointer. Alternatively it can be constructed from the constructor arguments bywith_args, likestd::make_uniquebut built into the type. A moved-fromBoxmay not be used except to be assigned to or destroyed. Using a moved-fromBoxwillpanicand terminate the program rather than operate on a null. This prevents Undefined Behaviour and memory bugs caused by dereferencing null or using null in unintended ways. - Supports up-casting (TODO: and
down-casting) without leaving requiring a native pointer to be pulled out of theBox. - No native arrays,
Boxcan holdArrayorstd::arraybut avoids API complexity for supporting pointers and native arrays (which decay to pointers) by rejecting native arrays. - Integration with concept type-erasure for
holding and constructing from type-erased objects which satisfy a given
concept in a type-safe way and without requiring inheritence. This
construction is done through
Fromand thus canBox<DynC>can be constructed in a type-deduced way from any object that satisfies the conceptCviasus::into(). This only requires thatDynCis compatible withDynConceptwhich is the case for all type-erasable concepts in the Subspace library. - Additional integration with Subspace library concepts like
ErrorandFnsuch thatBoxwill satisfy those concepts itself when holding a type-erased object that satisfies those concepts.
Box implements some concepts for its inner type
The Subspace library provides a number of concepts which support
type-erasure through DynConcept, and when
Box is holding these as its value, it may itself implement the concept,
forwarding use of the concept through to the inner type.
The canonical example of this is
Result<T, Box<DynError>>, which allows construction via
sus::err(sus::into(e)) for any e that satisfies
Error. The error field, now being a Box is still
usable as an Error allowing generic code that
expects the Result to hold an
Error to function even though the actual error has
been type-erased and no longer needs the functions to be templated on it.
The following concepts, when type-erased in Box will also be satisfied
by the Box itself, avoiding the need to unwrap the inner type and allowing
the Box to be used in templated code requiring that concept:
Static Methods
Constructs a Box which allocates space on the heap and moves T into it.
Constructs a Box which allocates space on the heap and moves T into it.
Converts U into a Box<T>.
The conversion allocates on the heap and moves u into it.
Satisfies the From<U> concept for
Box<T> where U is convertible to T and is not a
subclass of T.
Converts U into a Box<T>.
The conversion allocates on the heap and moves u into it.
Satisfies the From<U> concept for
Box<T> where U is T or a subclass of T.
For a type-erased DynC of a concept C, Box<DynC> can be
constructed from a type that satisfies C.
This satisfies the From<DynC, C> concept for
constructing Box<DynC> from any type that satisfies the concept C. It
allows returning a non-templated type satisfying a concept.
See DynConcept for more on type erasure of
concept-satisfying types.
Satisfies the From<std::string> concept for
Box<DynError>. This
conversion moves and type-erases the std::string into a heap-alloocated
DynError.
After calling this function, the raw pointer is owned by the resulting
Box. Specifically, the Box destructor will call the destructor of T and
free the allocated memory. For this to be safe, the memory must have been
allocated on the heap in the same way as the Box type, using
operator new and must not be
an array.
Constructs a Box by calling the constructor of T with args.
This allows construction of T directly on the heap, which is required
for types which do not satisfy Move. This is a common
case for virtual clases which require themselves to be heap allocated.
For type-erasure of concept objects using DynConcept, such as DynError,
the from constructor method
can be used to type erase the concept object and move it to the heap.
Constructs Box<T> with the default value for the type T.
Box can not satisfy Default because it
prevents C++ from using Box to build recursive types where T holds
an Option<Box<T>> as a member.
Methods
Converts Box into a mutable reference of the inner type.
Converts Box into a const reference of the inner type.
Returns a new box with a clone() of this box’s contents.
Copies source's contents into the contained T without creating a new
allocation.
An optimization to reuse the existing storage for
clone_into.
sus::iter::IteratorAny<T>
sus::iter::ExactSizeIterator<T, typename T::Item>
Implements ExactSizeIterator if
T is an ExactSizeIterator,
forwarding through to the inner T object.
Consumes the Box, returning the wrapped value.
This allows the caller to make use of the wrapped object as an rvalue
without leaving a moved-from T inside the Box.
Consumes the Box, returning a wrapped raw pointer.
The pointer will be properly aligned and non-null.
After calling this function, the caller is responsible for the memory
previously managed by the Box. In particular, the caller should properly
destroy T and
delete the
memory, taking into account the alignment if any that would be passed by
Box to operator new. The easiest
way to do this is to convert the raw pointer back back into a Box with
the Box::from_raw function, allowing the
Box destructor to perform the cleanup.
Note: this is a not a static function, unlike the matching Rust function
Box::into_raw,
since in C++ the Box can not expose the methods of the inner type
directly.
Examples
Converting the raw pointer back into a Box with
Box::from_raw for automatic cleanup:
auto x = Box<std::string>("Hello");
auto* ptr = sus::move(x).into_raw();
x = Box<std::string>::from_raw(unsafe_fn, ptr);
Manual cleanup by explicitly running the destructor and deallocating the memory:
auto x = Box<std::string>("Hello");
auto* p = sus::move(x).into_raw();
delete p;
Consumes and leaks the Box, returning a mutable reference, T&. Note
that the type T must outlive the returned reference.
This function is mainly useful for data that lives for the remainder of
the program's life. Dropping the returned reference will cause a memory
leak. If this is not acceptable, the reference should first be wrapped
with the Box::from_raw method producing a
Box. This Box can then be dropped which will properly destroy T and
release the allocated memory.
This method is not functionally different than into_raw but expresses a different intent, and returns
a reference type indicating it can not ever return null.
Note: unlike with the Rust Box::leak
this is not a static method, since Box can not expose the inner type's
methods directly in C++.
Implements DoubleEndedIterator if
T is a DoubleEndedIterator,
forwarding through to the inner T object.
Operators
T::IsDynFn
sus::fn::Fn<T, sus::fn::Return<T, Args...> (Args...)>
T::IsDynFn
sus::fn::FnMut<T, sus::fn::ReturnMut<T, Args...> (Args...)>
T::IsDynFn
sus::fn::FnOnce<T, sus::fn::ReturnOnce<T, Args...> (Args...)>
A Box holding a type-erased function type will satisfy the fn concepts
and can be used as a function type. It will forward the call through
to the inner type.
The usual compatibility rules apply, allowing DynFn
to be treated like DynFnMut
and both of them to be treated like DynFnOnce.
A Box<DynFnOnce> must be moved from
when called, and will destroy the
underlying function object after the call completes.
Examples
A Box<DynFn> being used as a function object:
const auto b = Box<sus::fn::DynFn<usize(std::string_view)>>::from(
&std::string_view::size);
sus_check(b("hello world") == 11u);
auto mut_b = Box<sus::fn::DynFn<usize(std::string_view)>>::from(
&std::string_view::size);
sus_check(mut_b("hello world") == 11u);
sus_check(sus::move(mut_b)("hello world") == 11u);
// The object inside `mut_b` is now destroyed.
A Box<DynFnMut> being used as a function object. It can not be called
on a const Box as it requies the ability to mutate, and const Box
treats its inner object as const:
auto mut_b = Box<sus::fn::DynFnMut<usize(std::string_view)>>::from(
&std::string_view::size);
sus_check(mut_b("hello world") == 11u);
sus_check(sus::move(mut_b)("hello world") == 11u);
// The object inside `mut_b` is now destroyed.
A Box<DynFnOnce> being used as a function object. It must be an rvalue
(either a return from a call or moved with move)
to call through it:
auto b = Box<sus::fn::DynFnOnce<usize(std::string_view)>>::from(
&std::string_view::size);
sus_check(sus::move(b)("hello world") == 11u);
auto x = [] {
return Box<sus::fn::DynFnOnce<usize(std::string_view)>>::from(
&std::string_view::size);
};
sus_check(x()("hello world") == 11u);