当Rc :: downgrade()做什么时,为什么Weak :: new()工作的后续工作呢?
当试图以Weak::new()
一种不需要它为底层类型分配内存的方式实现时,即使它永远不会被使用,我遇到了障碍.
定义RcBox<T>
很简单:
struct RcBox<T: ?Sized> {
strong: Cell<usize>,
weak: Cell<usize>,
value: T,
}
Run Code Online (Sandbox Code Playgroud)
这里的目标是创建一个RcBox<T>
实际上不包含任何内容的内容value
.基本上,一个RcBox<()>
.
然而,有一个障碍.*mut RcBox<()>
是一个瘦指针,但*mut RcBox<T>
可能是一个胖指针.我们有这个胖指针的数据部分,但有很多不同的胖指针的情况,所以试图合成其余的很难.
从链接的问题中可以看出,我可以使它适用于特征对象:
impl<T: ?Sized> Weak<T> {
pub fn new() -> Weak<T> {
unsafe {
let boxed = Box::into_raw(box RcBox {
strong: Cell::new(0),
weak: Cell::new(1),
value: (),
});
let ptr = if size_of::<*mut ()>() == size_of::<*mut T>() {
let ptr: *mut RcBox<T> = transmute_copy(&boxed);
ptr
} else {
let ptr: *mut RcBox<T> = transmute_copy(&TraitObject {
data: boxed as *mut (),
vtable: null_mut(),
});
ptr
};
Weak { ptr: Shared::new(ptr) }
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是这不适用于str
(例如).
我尝试隔离固定大小的部分,RcBox
同时让编译器推断指针的胖部分:
struct RcBox<T: ?Sized> {
counters: RcBoxCounters<T>,
value: T,
}
struct RcBoxCounters<T: ?Sized> {
strong: Cell<usize>,
weak: Cell<usize>,
_phantom: PhantomData<T>,
}
impl<T: ?Sized> Weak<T> {
pub fn new() -> Weak<T> {
unsafe {
let boxed = Box::into_raw(box RcBox::Counters::new(0, 1));
Weak { ptr: Shared::new(boxed as *mut RcBox<T>) }
}
}
}
Run Code Online (Sandbox Code Playgroud)
这听起来非常聪明,直到编译器压缩你的热情:
Run Code Online (Sandbox Code Playgroud)error[E0375]: implementing the trait `CoerceUnsized` requires multiple coercions --> <anon>:58:40 | 58 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<RcBox<U>> for RcBox<T> {} | ^^^^^^^^^^^^^^^^^^^^^^^ requires multiple coercions | = note: `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced = note: currently, 2 fields need coercions: counters (RcBoxCounters<T> to RcBoxCounters<U>), value (T to U)
那是:
PhantomData
在RcBoxCounters
,那么,有没有办法解决Weak::new()
它停止分配无关(不必要的)内存?
注意:我的意思是只为两个计数器分配空间,分配大和后续修剪无济于事.
注意:有人指出,人们可以使用Option
或特殊值来表示缺乏价值.这需要在每种方法上进行分支,这可能是不可取的.我更喜欢学会摆弄胖指针.
是的,有办法,而且居然提交到了标准库:
此更改使得 Weak::new() 根本不分配内存。相反,它是用空指针创建的。Weak 所做的唯一事情就是尝试升级、克隆和删除,这意味着代码实际上需要检查指针是否为空的地方很少。