Fat & Thin Pointer

Thin pointer

  • A thin pointer only contains the memory address it points to.

#![allow(unused)]
fn main() {
let a = 10;
let ra = &a;
println!("{:p}", &a);
println!("{:p}", ra);

assert_eq!(format!("{:p}", &a), format!("{:p}", ra));

let rra = &ra;
println!("{:p}", &ra);
println!("{:p}", rra);
assert_eq!(format!("{:p}", &ra), format!("{:p}", rra));
}

Fat pointer

A fat pointer contains both the address of a memory location it points to and additional metadata like the length of the allocation or a pointer to vtable in Trait Object.

&[T], &mut [T], &str are fat pointers

A reference to a slice [T] or str is a fat pointer, carrying the starting address of the slice and its length. [T] and str are dynamically sized types and that's the reason we see them as &[T], &mut [T] and &str.

The representation of &[T], &mut [T], &str might look like below:


#![allow(unused)]
fn main() {
struct SliceRef {
    ptr : *const i32
    len : usize
}
}

#![allow(unused)]
fn main() {
let arr : [i32; 5] = [1, 2, 3, 4, 5]; 
let slice_arr : &[i32] = &arr[..3];
println!("{slice_arr:?}");
println!("{:p}", &arr);
println!("{:p}", slice_arr);
assert_eq!(format!("{:p}", &arr), format!("{:p}", slice_arr));

println!("{}", std::mem::size_of::<i32>()); // 4 bytes
println!("{}", std::mem::size_of::<[i32; 5]>()); // 4 * 5 = 20 bytes

// size of the pointer pointing to value of type [i32; 5] 
println!("{}", std::mem::size_of::<&[i32; 5]>()); // 8 bytes

// &[i32] is a fat pointer
println!("{}", std::mem::size_of::<&[i32]>()); // 16 bytes

// &str is a fat pointer
println!("{}", std::mem::size_of::<&str>()); // 16 bytes
}

Trait Object is a fat pointer

A reference to a trait type is called a trait object. A Trait Object consists of a pointer to the value, plus a pointer to a table representing that value's type.


#![allow(unused)]
fn main() {
let mut buf = Vec::new();
let writer : &mut dyn std::io::Write = &mut buf;

println!("{}", std::mem::size_of::<Vec<i32>>()); // 24 bytes - buffer, capacity, length
println!("{}", std::mem::size_of::<Vec<String>>()); // 24 bytes bytes - buffer, capacity, length

println!("{}", std::mem::size_of::<&dyn std::io::Write>()); // 16 bytes
}

image