Why doesn't Weak::new() work when Rc::downgrade() does?
的后续行动当尝试以一种不要求它为底层类型分配内存的方式实现Weak::new()
时,即使它永远不会被使用,我也遇到了障碍。
RcBox<T>
的定义相当简单:
struct RcBox<T: ?Sized> {
strong: Cell<usize>,
weak: Cell<usize>,
value: T,
}
此处的目标是创建一个实际上不包含任何RcBox<T>
的{{1}}。基本上是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) }
}
}
}
合作(例如)。
我再次尝试隔离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>) } } } }
那是:
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()
或特殊值来表示缺少价值。这需要在每种方法上进行分支,这可能是不可取的。我更喜欢学会摆弄肥胖的指针。
答案 0 :(得分:2)
是的,有一种方法,它实际上已提交到标准库:
此更改使Weak :: new()完全不分配内存。而是使用空指针创建它。使用弱项完成的唯一工作就是尝试升级,克隆和删除,这意味着代码实际上很少需要检查指针是否为空的地方。