Bounds checks on slice element accesses are not usually a performance problem in programs. But these checks can slow down programs slightly.
In Rust, a direct access of a slice may have bounds checks that are not optimized out. A call to get_unchecked
, though, never has bounds checks.
Consider this Rust program. It creates an vector of 10000 elements, and then assigns a value somewhere in the middle of the vector.
get_unchecked()
in an unsafe block of code to test elements in the vector. No bounds checks are used in this loop.get_unchecked
is clear and reproducible. The bounds checks cause a significant performance reduction.fn main() { // Vector for testing. let mut x = vec![]; for _ in 0..10000 { x.push(0); } x[5555] = 5; // Version 1: use checked slice accesses. let t = Instant::now(); let mut count = 0; for _ in 0..100000 { for j in 10..9900 { if x[j] == 5 { count += 1; } } } println!("{}", t.elapsed().as_millis()); // Version 2: use get_unchecked. let t = Instant::now(); for _ in 0..100000 { for j in 10..9900 { unsafe { if *x.get_unchecked(j) == 5 { count += 1; } } } } println!("{}", t.elapsed().as_millis()); println!("{}", count); }468 ms x[j] 314 ms *x.get_unchecked(j) 200000
Calling get_unchecked
in Rust program always will involve some risk. It should only be used when you are absolutely certain it is correct.
get_unchecked
on invalid memory addresses, and unexpected values will be returned. The program may not terminate.Using get_checked
in Rust can significantly speed up some functions that repeatedly read elements from a slice. But the optimization is not safe, and must be carefully considered.