Rc与Box区别

来源:互联网 发布:手机淘宝彩票在哪里 编辑:程序博客网 时间:2024/06/10 20:40

咋一看觉得这两个概念差的很远,其实他们之间还是有联系的:

  • 相同点:
    他们都是在堆上分配资源,都只是保存了一个指向堆上的指针
  • 区别:
    • Box就是一个简单的指向堆的指针,并且指向堆的这个区域的指针只能有一个,owner lifetime结束就会释放堆上的资源
    • Rc增加了一个计数(准确来说是两个指针),可以多个指针指向堆的这个区域,等所有的引用者lifetime结束了才释放堆上的资源

下面的代码为了看起来清爽点删除了注释

1 这个是Rc的定义

struct RcBox<T: ?Sized> {    strong: Cell<usize>,    weak: Cell<usize>,    value: T,}pub struct Rc<T: ?Sized> {    _ptr: NonZero<*mut RcBox<T>>,}

其中NonZero很简单,就是简单的包装了下T

pub struct NonZero<T: Zeroable>(T);

具体可以看:
http://doc.rust-lang.org/stable/src/alloc/rc.rs.html#172

2 Box定义如下:

pub struct Box<T>(Unique<T>);

http://doc.rust-lang.org/stable/src/alloc/boxed.rs.html#94

其中Unique定义如下:

pub struct Unique<T: ?Sized> {    pointer: NonZero<*const T>,    _marker: PhantomData<T>,}

http://doc.rust-lang.org/stable/src/core/ptr.rs.html#513-521
Unique里的marker是不占用存储空间的,可以暂时忽略掉

3 具体的例子:

use std::rc::Rc;#[derive(Debug)]struct Foo(i32);fn main(){    let r:Rc<Foo>;    let b:Box<Foo>;    {        let r1 = Rc::new(Foo(100));        println!("r1:{:p}",&*r1);        //clone计数        r = r1.clone();        //多处引用,都可以分别访问        println!("r1:{:?}",r1);        let b1 = Box::new(Foo(200));        println!("b1:{:p},data:{}",&*b1,(*b1).0);        //owner ship 转移了        b = b1;        //b1不能再访问        //println!("{:?}",b1);    }    println!("{:?}",r);    println!("r:{:p}",&*r);    println!("{:?}",b);    println!("b:{:p}",&*b);}

Play地址:http://is.gd/rGBLaW
输出结果:

r1:0x7f621582d010r1:Foo(100)b1:0x7f6215823020,data:200Foo(100)r:0x7f621582d010Foo(200)b:0x7f6215823020

Box,Rc 都是在堆上分配的,那么都可以存在于定义它的范围之外。

  • Rc是通过引用计数的方式获得更长的lifetime,这儿r=r1.clone()就把堆上的对象的lifetime增加到了外层block对应的lifetime
  • Box通过转移owner ship的方式把b1传递给了b从而让Box指向的堆上的资源没有被释放。

在这种情况下都可以通过不同的方式实现lifetime的扩张,但还是有区别的:

  • Box方式转移了owner ship之后就不能再访问原来的b1了,也就是只能一个指针指向Box在堆上分配的资源
  • Rc通过增加引用计数的方式实现了lifetime的扩张,并且r1还是继续使用的
0 0
原创粉丝点击