首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么std::rc::Rc需要PhantomData?

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

Stack Overflow用户
提问于 2019-09-20 11:50:29
回答 1查看 955关注 0票数 13

我知道,PhantomData的目的是在数据类型定义中使用一个生存期参数或类型参数,否则这些参数将被闲置。我最近查看了Rc锈病性性病库中的定义,并注意到它似乎使用了PhantomData,但看起来T在兄弟字段ptr中被用作NonNull>。docs说NonNull但非零和协变。“,然后用以下语句进一步扩展了这个定义:

*mut T不同,NonNull<T>在T上是协变的。如果这对于您的用例来说是不正确的,您应该在您的类型中包含一些PhantomData以提供不变性,例如PhantomData<Cell<T>>PhantomData<&'a mut T>

因此,它是否需要方差,还是更多地是因为NonNull实际上是一个原始指针,而PhantomData则需要将被省略的生命周期作为这个答案似乎意味着使用。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-09-20 20:15:56

这里使用PhantomData告诉drop检查器正在删除Rc<T> 被丢弃

当我们宣布可以删除一个类型为T的值时,drop检查器确保T中的任何生命周期都会超过struct本身。正是这个检查阻止了以下代码的编译。在本例中,Rc的泛型参数是PeekOnDrop<&'a u8>,它具有生存期'a

代码语言:javascript
复制
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检查器递归地检查PeekOnDropPeekOnDrop文件并发现它可以访问T时,才会发生错误。

为了完整起见,下面是一个未定义程序的示例通过断言PeekOnDropDrop impl没有使用#[may_dangle]访问T。如果Rc没有使用PhantomData来声明它可能会删除T值,那么同样的未定义行为将在最初的示例中显示出来。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58027838

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档