我知道,PhantomData的目的是在数据类型定义中使用一个生存期参数或类型参数,否则这些参数将被闲置。我最近查看了Rc在锈病性性病库中的定义,并注意到它似乎使用了PhantomData,但看起来T在兄弟字段ptr中被用作NonNull>。docs说NonNull是但非零和协变。“,然后用以下语句进一步扩展了这个定义:
与
*mut T不同,NonNull<T>在T上是协变的。如果这对于您的用例来说是不正确的,您应该在您的类型中包含一些PhantomData以提供不变性,例如PhantomData<Cell<T>>或PhantomData<&'a mut T>。
因此,它是否需要方差,还是更多地是因为NonNull实际上是一个原始指针,而PhantomData则需要将被省略的生命周期作为这个答案似乎意味着使用。
发布于 2019-09-20 20:15:56
这里使用PhantomData告诉drop检查器正在删除Rc<T> 被丢弃。
当我们宣布可以删除一个类型为T的值时,drop检查器确保T中的任何生命周期都会超过struct本身。正是这个检查阻止了以下代码的编译。在本例中,Rc的泛型参数是PeekOnDrop<&'a u8>,它具有生存期'a。
use std::{fmt, rc::Rc};
struct PeekOnDrop<T: fmt::Debug>(T);
impl<T: fmt::Debug> Drop for PeekOnDrop<T> {
fn drop(&mut self) {
println!("{:?}", self.0);
}
}
struct SelfReferential<'a> {
value: Box<u8>,
rc: Option<Rc<PeekOnDrop<&'a u8>>>,
}
fn main() {
let mut sr = SelfReferential {
rc: None,
value: Box::new(1),
};
sr.rc = Some(Rc::new(PeekOnDrop(&*sr.value)));
// `sr` would be dropped here, which could drop `value` before `rc`.
// The destructor of `PeekOnDrop` would then try to inspect the (dangling)
// reference, resulting in UB!
}有关这里的底层逻辑的完整解释,请参见名字符号,但请注意,如果没有PeekOnDrop,前面的示例编译得很好。这是因为Rc<T>在其实施中声明其泛型参数T为#[may_dangle]。在这样做时,它承诺它的Drop impl对它所拥有的T值不做任何事情,除了(可能)放弃它。只有当drop检查器递归地检查PeekOnDrop的PeekOnDrop文件并发现它可以访问T时,才会发生错误。
为了完整起见,下面是一个未定义程序的示例通过断言PeekOnDrop的Drop impl没有使用#[may_dangle]访问T。如果Rc没有使用PhantomData来声明它可能会删除T值,那么同样的未定义行为将在最初的示例中显示出来。
https://stackoverflow.com/questions/58027838
复制相似问题