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()
能保证任何“永久”堆地址(在我的实现的有限上下文中)吗?
上面的代码看起来很安全,因为在
deref()
上调用 String
会给出一个指向堆的宽指针,并且该地址永远不会改变,除非字符串本身被更改或所有权返回给调用者。
请注意,我需要为我的用例存储
&str
,而不是使用用 ManuallyDrop<String>
创建的 ManuallyDrop::new(unsafe { ptr::read(&value) })
。
正如您所怀疑的,这并不安全。
stable_deref_trait
,它提供了应该用于此类用例的 StableDeref
特征。然而,这个特性被认为是不健全的(或者至少以不健全的方式使用),因为,例如,它实现了StableDeref
,但尚不清楚是否可以在其中移动Box
是对它的引用(在 Stacked Borrows 下,这是 UB,Miri 会将其标记为这样)。
如果你想100%安全,堆分配所有存储的对象并将它们存储为
*mut T
(不是Box<T>
,原因如上所述),然后你可以在同一个结构中存储对它们的引用。