use std::ops::Deref;
struct Test {
last: &'static str,
list: Vec<String>,
}
// This is safe because we own the value and will not modify it.
// When dropping, `last` will be dropped without freeing the memory.
impl Test {
pub fn new(value: String) -> Self {
Self {
last: unsafe { std::mem::transmute(value.deref()) },
list: vec![value],
}
}
pub fn insert(&mut self, value: String) {
self.last = unsafe { std::mem::transmute(value.deref()) };
self.list.push(value);
}
pub fn last(&self) -> &str {
self.last
}
}
字符串
有没有可能用泛型做类似的构造,比如Test<T:Deref>
?我不确定deref()
是否保证任何“永久”堆地址(在我的实现的有限上下文中),或者它是否保证了?
上面的代码看起来是安全的,因为在String
上调用deref()
会给出一个指向堆的宽指针,并且该地址永远不会改变,除非字符串本身被更改或所有权被返回给调用者。
请注意,我需要为我的用例存储&str
,而不是使用ManuallyDrop::new(unsafe { ptr::read(&value) })
创建的ManuallyDrop<String>
。
1条答案
按热度按时间vom3gejh1#
如你所料,这不安全。
存在
stable_deref_trait
,它提供了StableDeref
特征,应该用于这种用例。然而,this crate is known to be unsound(或者至少,以不合理的方式使用),因为,例如,它为Box
but it is not clear whether it is okay to move aBox
while there are references to it实现了StableDeref
(在Stacked Borrows下,这是UB,Miri将标记它)。如果你想100%安全,堆分配所有存储的对象,并将它们存储为
*mut T
(不是Box<T>
,因为上面提到的原因),那么你可以将它们的引用存储在同一个结构中。