我目前正在研究doing more stuff with arrays,但我认为如果允许我们以某种方式转换为前面的Leaked<T>
阵列,那么这些操作的性能可能会更好当功能结束时,将其泄漏。这将让我们使用泄漏放大,而不会a)引入不安全因素和b)设置catch_panic(_)
。这在Rust中是否有可能?
例如,从迭代器创建一个通用数组(这显然不起作用):
#[inline]
fn map_inner<I, S, F, T, N>(list: I, f: F) -> GenericArray<T, N>
where I: IntoIterator<Item=S>, F: Fn(&S) -> T, N: ArrayLength<T> {
unsafe {
// pre-leak the whole array, it's uninitialized anyway
let mut res : GenericArray<Leaked<T>, N> = std::mem::uninitialized();
let i = list.into_iter();
for r in res.iter_mut() {
// this could panic anytime
std::ptr::write(r, Leaked::new(f(i.next().unwrap())))
}
// transmuting un-leaks the array
std::mem::transmute::<GenericArray<Leaked<T>, N>,
GenericArray<T, N>>(res)
}
}
我应该注意,如果我们要么具有T
大小的编译时访问权限,要么可以隐藏其内涵的类型(如示例中的Leaked<T>
),这是完全可行的
答案 0 :(得分:3)
可以使用nodrop,但它可能会泄漏。
fn map_inner<I, S, F, T, N>(list: I, f: F) -> GenericArray<T, N>
where I: IntoIterator<Item=S>, F: Fn(&S) -> T, N: ArrayLength<T> {
unsafe {
// pre-leak the whole array, it's uninitialized anyway
let mut res : NoDrop<GenericArray<T, N>> = NoDrop::new(std::mem::uninitialized());
let i = list.into_iter();
for r in res.iter_mut() {
// this could panic anytime
std::ptr::write(r, f(i.next().unwrap()))
}
res.into_inner()
}
}
假设在第一项(a
)从i
消耗并写入r
后,发生恐慌。 i
中的其余项目将会丢弃,但项目a
则不会。虽然泄漏的记忆is not被认为是不安全的,但这是不可取的。