gpt4 book ai didi

pointers - 什么是 "fat pointer"?

转载 作者:行者123 更新时间:2023-11-29 07:40:05 31 4
gpt4 key购买 nike

我已经在多个上下文中读到术语“胖指针”,但我不确定它的确切含义以及它在 Rust 中的使用时间。指针好像是普通指针的两倍大,但我不明白为什么。它似乎也与特征对象有关。

最佳答案

术语“胖指针”用于指代对动态大小类型 (DST) – 切片或特征对象的引用和原始指针。一个胖指针包含一个指针加上一些使 DST “完整”的信息(例如长度)。

Rust 中最常用的类型不是 DST,但在编译时具有已知的固定大小。这些类型实现了 the Sized trait .甚至管理动态大小的堆缓冲区的类型(如 Vec<T> )也是 Sized ,因为编译器知道确切的字节数 a Vec<T>实例将占用堆栈。目前 Rust 中有四种不同的 DST。


切片([T]str)

类型[T] (对于任何 T )是动态大小的(特殊的“字符串切片”类型 str 也是如此)。这就是为什么您通常只将其视为 &[T] 的原因。或 &mut [T] ,即在引用后面。该引用是所谓的“胖指针”。让我们检查一下:

dbg!(size_of::<&u32>());
dbg!(size_of::<&[u32; 2]>());
dbg!(size_of::<&[u32]>());

这会打印(经过一些清理):

size_of::<&u32>()      = 8
size_of::<&[u32; 2]>() = 8
size_of::<&[u32]>() = 16

所以我们看到对普通类型的引用,如 u32是 8 个字节大,就像对数组的引用一样 [u32; 2] .这两种类型不是 DST。但是作为[u32]是 DST,对它的引用是两倍大。 在切片的情况下,“完成”DST 的附加数据就是长度。因此可以说 &[u32] 的表示形式是这样的:

struct SliceRef { 
ptr: *const u32,
len: usize,
}

特征对象 ( dyn Trait )

当使用 trait 作为 trait 对象时(即类型删除、动态调度),这些 trait 对象是 DST。示例:

trait Animal {
fn speak(&self);
}

struct Cat;
impl Animal for Cat {
fn speak(&self) {
println!("meow");
}
}

dbg!(size_of::<&Cat>());
dbg!(size_of::<&dyn Animal>());

这会打印(经过一些清理):

size_of::<&Cat>()        = 8
size_of::<&dyn Animal>() = 16

再次,&Cat只有 8 个字节大,因为 Cat是普通类型。但是dyn Animal是一个特征对象,因此动态调整大小。因此,&dyn Animal有 16 个字节大。

在 trait 对象的情况下,完成 DST 的附加数据是指向 vtable(vptr)的指针。我不能在这里完全解释 vtables 和 vptr 的概念,但它们是用于在此虚拟分派(dispatch)上下文中调用正确的方法实现。 vtable 是一个静态数据,基本上只包含每个方法的函数指针。这样,对特征对象的引用基本上表示为:

struct TraitObjectRef {
data_ptr: *const (),
vptr: *const (),
}

(这与 C++ 不同,在 C++ 中,抽象类的 vptr 存储在对象中。两种方法各有利弊。)


自定义夏令时

实际上可以通过最后一个字段是 DST 的结构来创建自己的 DST。不过,这种情况很少见。一个突出的例子是 std::path::Path .

自定义 DST 的引用或指针也是一个胖指针。附加数据取决于结构内 DST 的类型。


异常:外部类型

RFC 1861 , extern type功能被引入。外部类型也是 DST,但指向它们的指针不是胖指针。或者更准确地说,正如 RFC 所说:

In Rust, pointers to DSTs carry metadata about the object being pointed to. For strings and slices this is the length of the buffer, for trait objects this is the object's vtable. For extern types the metadata is simply (). This means that a pointer to an extern type has the same size as a usize (ie. it is not a "fat pointer").

但如果您不与 C 接口(interface)交互,您可能永远不必处理这些外部类型。




在上面,我们已经看到了不可变引用的大小。胖指针对于可变引用、不可变原始指针和可变原始指针的工作方式相同:

size_of::<&[u32]>()       = 16
size_of::<&mut [u32]>() = 16
size_of::<*const [u32]>() = 16
size_of::<*mut [u32]>() = 16

关于pointers - 什么是 "fat pointer"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57754901/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com