是否可以让通用 Rust T 始终分配堆?

问题描述 投票:0回答:1
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) })

rust unsafe
1个回答
0
投票

正如您所怀疑的,这并不安全。

存在

stable_deref_trait
,它提供了应该用于此类用例的
StableDeref
特征。然而,这个特性被认为是不健全的(或者至少以不健全的方式使用),因为,例如,它实现了
StableDeref
,但尚不清楚是否可以在其中移动
Box
是对它的引用
(在 Stacked Borrows 下,这是 UB,Miri 会将其标记为这样)。

如果你想100%安全,堆分配所有存储的对象并将它们存储为

*mut T
不是
Box<T>
,原因如上所述),然后你可以在同一个结构中存储对它们的引用。

© www.soinside.com 2019 - 2024. All rights reserved.