加入收藏 | 设为首页 | 会员中心 | 我要投稿 焦作站长网 (https://www.0391zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长资讯 > 传媒 > 正文

分析智能指针 Box 的神秘面纱

发布时间:2021-10-08 15:47:19 所属栏目:传媒 来源:互联网
导读:熟悉 c++ 的肯定知道 shared_ptr, unique_ptr, 而 Rust 也有智能指针 Box, Rc, Arc, RefCell 等等,本文分享 Box 底层实现 Box T会在堆上分配空间,存储 T 值,

Box <T>会在堆上分配空间,存储 T 值,并返回对应的指针。同时 Box 也实现了 trait Deref 解引用和 Drop 析构,当 Box 离开作用域时自动释放空间

 

入门例子

例子来自 the rust book, 为了演示方便,去掉打印语句

 

fn main() { 

    let _ = Box::new(0x11223344); 

将变量 0x11223344 分配在堆上,所谓的装箱,java 同学肯定很熟悉。让我们挂载 docker, 使用 rust-gdb 查看汇编实现ASP站长网

 

Dump of assembler code for function hello_cargo::main: 

   0x000055555555bdb0 <+0>: sub    $0x18,%rsp 

   0x000055555555bdb4 <+4>: movl   $0x11223344,0x14(%rsp) 

=> 0x000055555555bdbc <+12>: mov    $0x4,%esi 

   0x000055555555bdc1 <+17>: mov    %rsi,%rdi 

   0x000055555555bdc4 <+20>: callq  0x55555555b5b0 <alloc::alloc::exchange_malloc> 

   0x000055555555bdc9 <+25>: mov    %rax,%rcx 

   0x000055555555bdcc <+28>: mov    %rcx,%rax 

   0x000055555555bdcf <+31>: movl   $0x11223344,(%rcx) 

   0x000055555555bdd5 <+37>: mov    %rax,0x8(%rsp) 

   0x000055555555bdda <+42>: lea    0x8(%rsp),%rdi 

   0x000055555555bddf <+47>: callq  0x55555555bd20 <core::ptr::drop_in_place<alloc::boxed::Box<i32>>> 

   0x000055555555bde4 <+52>: add    $0x18,%rsp 

   0x000055555555bde8 <+56>: retq 

End of assembler dump. 

关键点就两条,alloc::alloc::exchange_malloc 在堆上分配内存空间,然后将 0x11223344 存储到这个 malloc 的地址上

 

函数结束时,将地址传递给 core::ptr::drop_in_place 去释放,因为编译器知道类型是 alloc::boxed::Box, 会掉用 Box 相应的 drop 函数

 

单纯的看这个例子,Box 并不神秘,对应汇编实现,和普通指针没区别,一切约束都是编译期行为

 

所有权

fn main() { 

    let x = Box::new(String::from("Rust")); 

    let y = *x; 

    println!("x is {}", x); 

这个例子中将字符串装箱,其实没必要这么写,因为 String 广义来讲本身就是一种智能指针。这个例子会报错

 

3 |     let y = *x; 

  |             -- value moved here 

4 |     println!("x is {}", x); 

  |                         ^ value borrowed here after move 

*x 解引用后对应 String, 赋值给 y 时执行 move 语义,所有权不在了,所以后续 println 不能打印 x

 

let y = &*x; 

可以取字符串的不可变引用来 fix

 

底层实现

pub struct Box< 

    T: ?Sized, 

    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, 

>(Unique<T>, A); 

上面是 Box 的定义,可以看到是一个元组结构体,有两个泛型参数:T 代表任意类型,A 代表内存分配器。标准库里 A 是 Gloal 默认值。其中 T 有一个泛型约束 ?Sized, 表示在编译时可能知道类型大小,也可能不知道,当然一般都用于不知道大小的场景,很少像上文一样存储 int

(编辑:焦作站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读