由于它不知道数据的具体类型,因此仅包含dyn Trait的vtpr,如果超出范围,它将如何丢弃? Rust中的每个虚拟表都包含drop方法的实现吗?
答案 0 :(得分:5)
当包含的原始类型r1 + r2
的具体类型未调整为特征对象的大小时,该类型的Box
实现将进入vtable。指针(其指针是特征对象)的指针(Rust。IE中的任何类似指针的东西,引用,Drop
,原始指针等)在内存中的布局如下:
Box
在我的示例中,struct FooTraitDynPointer {
ptr: *[const/mut] (),
vtable: &'static VTableImplForFooTrait
}
字段指向实际数据。我们可以说这是原始的ptr
。
在我的示例中,Box
字段指向静态vtable。假设我们具有以下vtable
特征:
Foo
我们的vtable如下*:
trait Foo {
fn bar(&self) -> usize;
}
我们在这里看到struct VTableImplForFooTrait {
dropper: unsafe fn(*mut ()),
size: usize,
align: usize,
bar: unsafe fn(*const ()) -> usize,
}
在。伴随着它,还有size和align字段,这些字段允许拥有的类型释放足够的内存。或重新分配足够的内存。
这是一个示例程序,该程序从指向特征对象的指针中粗略提取结构的大小:
drop
(当前)打印:
#![feature(raw)]
trait Foo {
fn bar(&self) -> usize;
}
struct Baz {
field: f64
}
impl Foo for Baz {
fn bar(&self) -> usize {
self.field as usize
}
}
#[derive(Clone)]
struct FooVTable {
dropper: unsafe fn(*mut ()),
size: usize,
align: usize,
bar: unsafe fn(*const ()) -> usize,
}
fn main() {
use std::{mem, raw};
let value = Baz { field: 20.0 };
let boxed = Box::new(value) as Box<dyn Foo>;
let deconstructed: raw::TraitObject = unsafe { mem::transmute(boxed) };
let vtable = deconstructed.vtable as *mut FooVTable;
let vtable = unsafe { (*vtable).clone() };
println!("size: {}, align: {}", vtable.size, vtable.align);
let result = unsafe { (vtable.bar)(deconstructed.data) };
println!("Value: {}", result);
}
但是,将来这可能会发生很大的变化,因此我将这个时间戳留在这里,供将来在行为已更改的情况下阅读此时间戳的人使用。 2020年6月5日。
*:不不能保证特征对象的布局,尤其是其vtable的布局,因此不要依赖实际的代码。