Function std::hint::unreachable_unchecked
1.27.0 (const: 1.57.0) · source · pub const unsafe fn unreachable_unchecked() -> !
Expand description
通知编译器调用此函数的站点不可访问,可能会启用进一步优化。
Safety
达到这个函数是 未定义的行为。
由于编译器假定所有形式的未定义行为永远不会发生,它将消除周围代码中的所有分支,它可以确定总是会导致调用 unreachable_unchecked()
。
如果使用这个函数的假设被证明是错误的 – 也就是说,如果调用 unreachable_unchecked()
的站点在运行时实际上是可访问的 – 编译器可能已经为这种情况生成了无意义的机器指令,包括看似不相关的代码,导致难以 - 调试问题。
谨慎使用此功能。
考虑使用 unreachable!
宏,这可能会阻止一些优化,但如果在运行时实际达到它会安全地 panic。对您的代码进行基准测试,以确定使用 unreachable_unchecked()
是否具有性能优势。
Examples
unreachable_unchecked()
可用于编译器无法证明先前建立的不,变体,的情况。如果编译器无法分析的外部代码支持这些不,变体,则这种情况发生的可能性更高。
fn prepare_inputs(divisors: &mut Vec<u32>) {
// 更改时,注意 future-self: 这里建立的不变量没有在 `do_computation()` 中检查; 如果这种情况发生变化,您必须更改 `do_computation()`。
divisors.retain(|divisor| *divisor != 0)
}
/// # Safety
/// `divisor` 的所有元素都必须非零。
unsafe fn do_computation(i: u32, divisors: &[u32]) -> u32 {
divisors.iter().fold(i, |acc, divisor| {
// 让编译器相信这里不会发生被零除,并且下面不需要检查。
if *divisor == 0 {
// 安全性: 由于 `prepare_inputs`,`divisor` 不能为零,但编译器不知道这一点。
// 我们 *承诺* 我们总是调用 `prepare_inputs`。
std::hint::unreachable_unchecked()
}
// 编译器通常会在此处引入一个检查,以防止被零除。
// 但是,如果 `divisor` 为零,则上面的分支将到达我们明确标记为不可达的地方。
// 编译器得出结论,此时 `divisor` 不能为零,并删除 - 现在证明无用 - 检查。
acc / divisor
})
}
let mut divisors = vec![2, 0, 4];
prepare_inputs(&mut divisors);
let result = unsafe {
// 安全性: prepare_inputs() 保证除数不为零
do_computation(100, &divisors)
};
assert_eq!(result, 12);
Run虽然在以下示例中使用 unreachable_unchecked()
是完美的,因为编译器能够证明除以零是不可能的,但基准测试显示 unreachable_unchecked()
与使用 unreachable!
相比没有任何好处,而后者不会引入未定义行为的可能性。
fn div_1(a: u32, b: u32) -> u32 {
use std::hint::unreachable_unchecked;
// `b.saturating_add(1)` 始终为正 (非零),因此 `checked_div` 永远不会返回 `None`。
// 因此,else 分支不可访问。
a.checked_div(b.saturating_add(1))
.unwrap_or_else(|| unsafe { unreachable_unchecked() })
}
assert_eq!(div_1(7, 0), 7);
assert_eq!(div_1(9, 1), 4);
assert_eq!(div_1(11, u32::MAX), 0);
Run