1.0.0[][src]Module nom::lib::std::boxed

A pointer type for heap allocation.

Box<T>, casually referred to as a 'box', provides the simplest form of heap allocation in Rust. Boxes provide ownership for this allocation, and drop their contents when they go out of scope.

Examples

Move a value from the stack to the heap by creating a Box:

let val: u8 = 5;
let boxed: Box<u8> = Box::new(val);

Move a value from a Box back to the stack by dereferencing:

let boxed: Box<u8> = Box::new(5);
let val: u8 = *boxed;

Creating a recursive data structure:

#[derive(Debug)]
enum List<T> {
    Cons(T, Box<List<T>>),
    Nil,
}

let list: List<i32> = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));
println!("{:?}", list);

This will print Cons(1, Cons(2, Nil)).

Recursive structures must be boxed, because if the definition of Cons looked like this:

This example deliberately fails to compile
Cons(T, List<T>),

It wouldn't work. This is because the size of a List depends on how many elements are in the list, and so we don't know how much memory to allocate for a Cons. By introducing a Box<T>, which has a defined size, we know how big Cons needs to be.

Memory layout

For non-zero-sized values, a Box will use the Global allocator for its allocation. It is valid to convert both ways between a Box and a raw pointer allocated with the Global allocator, given that the Layout used with the allocator is correct for the type. More precisely, a value: *mut T that has been allocated with the Global allocator with Layout::for_value(&*value) may be converted into a box using Box::<T>::from_raw(value). Conversely, the memory backing a value: *mut T obtained from Box::<T>::into_raw may be deallocated using the Global allocator with Layout::for_value(&*value).

So long as T: Sized, a Box<T> is guaranteed to be represented as a single pointer and is also ABI-compatible with C pointers (i.e. the C type T*). This means that if you have extern "C" Rust functions that will be called from C, you can define those Rust functions using Box<T> types, and use T* as corresponding type on the C side. As an example, consider this C header which declares functions that create and destroy some kind of Foo value:

/* C header */

/* Returns ownership to the caller */
struct Foo* foo_new(void);

/* Takes ownership from the caller; no-op when invoked with NULL */
void foo_delete(struct Foo*);

These two functions might be implemented in Rust as follows. Here, the struct Foo* type from C is translated to Box<Foo>, which captures the ownership constraints. Note also that the nullable argument to foo_delete is represented in Rust as Option<Box<Foo>>, since Box<Foo> cannot be null.

#[repr(C)]
pub struct Foo;

#[no_mangle]
pub extern "C" fn foo_new() -> Box<Foo> {
    Box::new(Foo)
}

#[no_mangle]
pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {}

Even though Box<T> has the same representation and C ABI as a C pointer, this does not mean that you can convert an arbitrary T* into a Box<T> and expect things to work. Box<T> values will always be fully aligned, non-null pointers. Moreover, the destructor for Box<T> will attempt to free the value with the global allocator. In general, the best practice is to only use Box<T> for pointers that originated from the global allocator.

Important. At least at present, you should avoid using Box<T> types for functions that are defined in C but invoked from Rust. In those cases, you should directly mirror the C types as closely as possible. Using types like Box<T> where the C definition is just using T* can lead to undefined behavior, as described in rust-lang/unsafe-code-guidelines#198.

Structs

Box

A pointer type for heap allocation.