为什么std :: rc :: Rc需要PhantomData?

rjs*_*rjs 10 rust

我知道这PhantomData是要消耗数据类型定义中的生命周期或类型参数,否则将不使用该参数。我最近在看的定义Rc锈标准库,发现它似乎雇用PhantomData,但它看起来像T在同级领域正在被使用ptr作为NonNull<RcBox<T>>。文档说这NonNull“ * mut T,但非零且协变”。并通过以下语句进一步扩展该定义:

与相比*mut TNonNull<T>T 与T协变。如果这对于您的用例而言是不正确的,则应PhantomData在类型中包括一些以提供不变性,例如PhantomData<Cell<T>>PhantomData<&'a mut T>

因此,它是否需要方差还是更多,因为NonNull它实际上是原始指针,PhantomData并且需要消耗消亡的生命,因为这个答案似乎暗示了这一点

ecs*_*rse 5

PhantomData用来告诉丢弃检查器丢弃Rc<T> 可能导致类型值的T丢弃

当我们宣布可以删除type的值时T,删除检查器将确保所有生存期都T超过其struct自身。正是这种检查阻止了以下代码的编译。在这种情况下,Rcis 的通用参数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!
}
Run Code Online (Sandbox Code Playgroud)

有关此处的基本逻辑的完整说明,请参见nomicon,但请注意,如果没有PeekOnDrop,则前面的示例编译就可以了。这是因为Rc<T>在其Drop隐式中声明其通用参数T#[may_dangle]。通过这样做,它承诺其Dropimpl不T对其拥有的值做任何事情,除非(可能)删除它。仅当drop checker递归检查Dropimpl PeekOnDrop并发现它可以访问时,T才会发生错误。

为了完整起见,这里是一个不确定的程序的一个例子是谎言由声称PeekOnDropDropIMPL不访问T使用#[may_dangle]。如果原始示例Rc未用于PhantomData声明它可能会降低的值,则同样的未定义行为也会显示出来T