Box, Stack and Heap

RustRustBeginner
Practice Now

This tutorial is from open-source community. Access the source code

Introduction

In this lab, the concept of boxing, stack allocation, and heap allocation in Rust is explored. All values in Rust are stack allocated by default, but they can be boxed (allocated on the heap) using the Box<T> type. A box is a smart pointer to a heap-allocated value, and when it goes out of scope, its destructor is called and the memory on the heap is freed. Boxing allows for the creation of double indirection and can be dereferenced using the * operator. The lab provides code examples and explanations of how boxing works and how it affects memory allocation on the stack.

Note: If the lab does not specify a file name, you can use any file name you want. For example, you can use main.rs, compile and run it with rustc main.rs && ./main.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("`Rust`")) -.-> rust/BasicConceptsGroup(["`Basic Concepts`"]) rust(("`Rust`")) -.-> rust/DataTypesGroup(["`Data Types`"]) rust(("`Rust`")) -.-> rust/FunctionsandClosuresGroup(["`Functions and Closures`"]) rust(("`Rust`")) -.-> rust/DataStructuresandEnumsGroup(["`Data Structures and Enums`"]) rust(("`Rust`")) -.-> rust/AdvancedTopicsGroup(["`Advanced Topics`"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("`Variable Declarations`") rust/DataTypesGroup -.-> rust/floating_types("`Floating-point Types`") rust/DataTypesGroup -.-> rust/string_type("`String Type`") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("`Function Syntax`") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("`Expressions and Statements`") rust/DataStructuresandEnumsGroup -.-> rust/method_syntax("`Method Syntax`") rust/AdvancedTopicsGroup -.-> rust/operator_overloading("`Traits for Operator Overloading`") subgraph Lab Skills rust/variable_declarations -.-> lab-343181{{"`Box, Stack and Heap`"}} rust/floating_types -.-> lab-343181{{"`Box, Stack and Heap`"}} rust/string_type -.-> lab-343181{{"`Box, Stack and Heap`"}} rust/function_syntax -.-> lab-343181{{"`Box, Stack and Heap`"}} rust/expressions_statements -.-> lab-343181{{"`Box, Stack and Heap`"}} rust/method_syntax -.-> lab-343181{{"`Box, Stack and Heap`"}} rust/operator_overloading -.-> lab-343181{{"`Box, Stack and Heap`"}} end

Box, stack and heap

All values in Rust are stack allocated by default. Values can be boxed (allocated on the heap) by creating a Box<T>. A box is a smart pointer to a heap allocated value of type T. When a box goes out of scope, its destructor is called, the inner object is destroyed, and the memory on the heap is freed.

Boxed values can be dereferenced using the * operator; this removes one layer of indirection.

use std::mem;

#[allow(dead_code)]
#[derive(Debug, Clone, Copy)]
struct Point {
    x: f64,
    y: f64,
}

// A Rectangle can be specified by where its top left and bottom right
// corners are in space
#[allow(dead_code)]
struct Rectangle {
    top_left: Point,
    bottom_right: Point,
}

fn origin() -> Point {
    Point { x: 0.0, y: 0.0 }
}

fn boxed_origin() -> Box<Point> {
    // Allocate this point on the heap, and return a pointer to it
    Box::new(Point { x: 0.0, y: 0.0 })
}

fn main() {
    // (all the type annotations are superfluous)
    // Stack allocated variables
    let point: Point = origin();
    let rectangle: Rectangle = Rectangle {
        top_left: origin(),
        bottom_right: Point { x: 3.0, y: -4.0 }
    };

    // Heap allocated rectangle
    let boxed_rectangle: Box<Rectangle> = Box::new(Rectangle {
        top_left: origin(),
        bottom_right: Point { x: 3.0, y: -4.0 },
    });

    // The output of functions can be boxed
    let boxed_point: Box<Point> = Box::new(origin());

    // Double indirection
    let box_in_a_box: Box<Box<Point>> = Box::new(boxed_origin());

    println!("Point occupies {} bytes on the stack",
             mem::size_of_val(&point));
    println!("Rectangle occupies {} bytes on the stack",
             mem::size_of_val(&rectangle));

    // box size == pointer size
    println!("Boxed point occupies {} bytes on the stack",
             mem::size_of_val(&boxed_point));
    println!("Boxed rectangle occupies {} bytes on the stack",
             mem::size_of_val(&boxed_rectangle));
    println!("Boxed box occupies {} bytes on the stack",
             mem::size_of_val(&box_in_a_box));

    // Copy the data contained in `boxed_point` into `unboxed_point`
    let unboxed_point: Point = *boxed_point;
    println!("Unboxed point occupies {} bytes on the stack",
             mem::size_of_val(&unboxed_point));
}

Summary

Congratulations! You have completed the Box, Stack and Heap lab. You can practice more labs in LabEx to improve your skills.

Other Rust Tutorials you may like