Skip to content

Instantly share code, notes, and snippets.

@max-itzpapalotl
Last active February 18, 2024 22:21
Show Gist options
  • Save max-itzpapalotl/63966c058d896aac6c5771dea440bf31 to your computer and use it in GitHub Desktop.
Save max-itzpapalotl/63966c058d896aac6c5771dea440bf31 to your computer and use it in GitHub Desktop.
22. Smart pointers

22. Smart pointers

Box

This is just a unique pointer, cannot be cloned, single threaded.

#[derive(Debug)]
struct Person {
    pub name: String,
    pub age: u32,
}

fn main() {
    let mut b = Box::new(Person{name: "Max".into(), age: 54});
    b.age = 55;
    println!("Name: {}, Age: {}", b.name, b.age);
    println!("Byte size: {}", std::mem::size_of::<Box<Person>>());
}

std::rc::Rc

This is a reference counted pointer, can be cloned, if there is only one reference, one can get mutable access. Single threaded.

#[derive(Debug)]
struct Person {
    pub name: String,
    pub age: u32,
}

fn main() {
    let mut b = std::rc::Rc::new(Person{name: "Max".into(), age: 54});
    {
        let c = b.clone();
        println!("Name: {}, Age: {}", c.name, c.age);
    }
    {
        let m = std::rc::Rc::get_mut(&mut b);
        if let Some(p) = m {
            p.age = 55;
        } else {
            println!("Cannot get mutable reference!");
        }
    }
    println!("Name: {}, Age: {}", b.name, b.age);
    println!("Byte size: {}", std::mem::size_of::<std::rc::Rc<Person>>());
}

std::sync::Arc

Multi-threaded reference counted smart pointer using atomics for the reference count.

#[derive(Debug)]
struct Person {
    pub name: String,
    pub age: u32,
}

fn main() {
    let mut b = std::sync::Arc::new(Person{name: "Max".into(), age: 54});
    // let c = b.clone();
    {
        let m = std::sync::Arc::get_mut(&mut b);
        if let Some(p) = m {
            p.age = 55;
        } else {
            println!("Cannot get mutable reference!");
        }
    }
    println!("Name: {}, Age: {}", b.name, b.age);
    // println!("Name: {}, Age: {}", c.name, c.age);
    println!("Byte size: {}", std::mem::size_of::<std::sync::Mutex::<Person>>());
}

std::sync::Mutex

Mutex using the type system to ensure proper usage.

#[derive(Debug)]
struct Person {
    pub name: String,
    pub age: u32,
}

fn main() {
    let b = std::sync::Mutex::new(Person{name: "Max".into(), age: 54});
    {
        let g = b.lock();
        if let Ok(mut p) = g {
            p.age = 55;
        } else {
            println!("Cannot get mutex!");
        }
    }
    {
        let g = b.lock().unwrap();
        println!("Name: {}, Age: {}", g.name, g.age);
    }
    println!("Byte size: {}", std::mem::size_of::<std::sync::Mutex::<Person>>());
}

std::sync::RwLock

Read/Write lock using the type system to ensure proper usage.

#[derive(Debug)]
struct Person {
    pub name: String,
    pub age: u32,
}

fn main() {
    let b = std::sync::RwLock::new(Person{name: "Max".into(), age: 54});
    {
        let g = b.write();
        if let Ok(mut p) = g {
            p.age = 55;
        } else {
            println!("Cannot get mutex!");
        }
    }
    {
        let g = b.read().unwrap();
        println!("Name: {}, Age: {}", g.name, g.age);
    }
    println!("Byte size: {}", std::mem::size_of::<std::sync::RwLock::<Person>>());
}

std::cell::RefCell

Single threaded, run-time tracking immutable references and allows one mutable reference at a time.

#[derive(Debug)]
struct Person {
    pub name: String,
    pub age: u32,
}

fn main() {
    let b = std::cell::RefCell::new(Person{name: "Max".into(), age: 54});
    {
        let c = b.borrow();
        println!("Name: {}, Age: {}", c.name, c.age);
    }
    {
        b.borrow_mut().age = 55;
    }
    println!("Name: {}, Age: {}", b.borrow().name, b.borrow().age);
    println!("Byte size: {}", std::mem::size_of::<std::cell::RefCell<Person>>());
}

std::cell::Cell

Single threaded, allows mutation just be moving the value in and out.

#[derive(Debug)]
struct Person {
    pub name: String,
    pub age: u32,
}

fn main() {
    let b = std::cell::Cell::new(Person{name: "Max".into(), age: 54});
    b.replace(Person{name: "Max2".into(), age: 55});
    let c = b.into_inner();
    // println!("Name: {}, Age: {}", b.name, b.age);    // not allowed
    println!("Name: {}, Age: {}", c.name, c.age);
    println!("Byte size: {}", std::mem::size_of::<std::cell::Cell<Person>>());
}

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment