[英]How does Box<dyn Trait> deconstruct itself?
Since it doesn't know the concrete type of the data, it only contains a vtpr of dyn Trait, How does it drop itself when it goes out of scope?由于它不知道数据的具体类型,它只包含一个dyn Trait的vtpr,当它从scope出来时,它是如何掉线的? Does every virtual table in Rust contains a drop method implementation? Rust 中的每个虚拟表是否都包含删除方法实现?
When the concrete type the original Box
contained is unsized into a trait object, the Drop
implementation for the type goes into the vtable.当原始Box
包含的具体类型未调整大小为特征 object 时,该类型的Drop
实现进入 vtable。 A pointer (Any pointer-like thing in Rust. IE, a reference, Box
, raw pointer, etc.) whose pointee is a trait object is laid out as follows in memory*:指针(Rust.IE、引用、Box、原始指针等)的指针(Rust.IE、引用、 Box
、原始指针等)的指针是特征 object 在内存中的布局如下*:
struct FooTraitDynPointer {
ptr: *[const/mut] (),
vtable: &'static VTableImplForFooTrait
}
The ptr
field in my example points to the actual data.我示例中的ptr
字段指向实际数据。 We could say that's the original Box
.我们可以说那是原始的Box
。
The vtable
field in my example points to a static vtable.我的示例中的vtable
字段指向 static vtable。 Say we have the following Foo
trait:假设我们有以下Foo
特征:
trait Foo {
fn bar(&self) -> usize;
}
Our vtable will look as follows*:我们的 vtable 如下所示*:
struct VTableImplForFooTrait {
dropper: unsafe fn(*mut ()),
size: usize,
align: usize,
bar: unsafe fn(*const ()) -> usize,
}
We see there, that the drop
is there.我们在那里看到, drop
就在那里。 Along with it, there're size and align fields which allow owning types to deallocate enough memory.除此之外,还有大小和对齐字段,允许拥有类型释放足够的 memory。 Or re-allocate enough memory.或者重新分配足够的memory。
Here's an example program which crudely extracts the size of a struct from within a pointer to a trait object:这是一个示例程序,它从指向特征 object 的指针中粗略地提取结构的大小:
#![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);
}
(Currently) prints: (当前)打印:
size: 8, align: 8
Value: 20
However this may very well change in the future so I'm leaving this timestamp here for someone who reads this in a future where the behaviour has been changed.然而,这在未来很可能会发生变化,所以我将把这个时间戳留给那些在未来阅读这个行为已经改变的人。 June 5, 2020. 2020 年 6 月 5 日。
*: The layout of trait objects, and especially their vtables is NOT guaranteed, so do not rely in actual code. *:不能保证 trait 对象的布局,尤其是它们的 vtables,所以不要依赖于实际代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.