您可以使用零大小类型(简称 ZST)来获取您想要的 API,而无需另一个指针的开销。
这是 2 个池的实现,可以扩展为支持任意数量的池,使用宏生成“标记”结构(P1
、、P2
等)。一个主要的缺点是忘记free
使用池会“泄漏”内存。
这篇Ferrous Systems 博客文章有许多您可能感兴趣的改进,尤其是在您静态分配池的情况下,并且它们还有许多技巧可以P1
让用户无法滥用 API。
use std::marker::PhantomData;
use std::{cell::RefCell, mem::size_of};
struct Index<D>(usize, PhantomData<D>);
struct Pool<D> {
data: Vec<[u8; 4]>,
free_list: RefCell<Vec<bool>>,
marker: PhantomData<D>,
}
impl<D> Pool<D> {
fn new() -> Pool<D> {
Pool {
data: vec![[0,0,0,0]],
free_list: vec![true].into(),
marker: PhantomData::default(),
}
}
fn allocate(&self) -> Index<D> {
self.free_list.borrow_mut()[0] = false;
Index(0, self.marker)
}
fn free<'a>(&self, item: Index<D>) {
self.free_list.borrow_mut()[item.0] = true;
}
}
struct P1;
fn create_pool1() -> Pool<P1> {
assert_eq!(size_of::<Index<P1>>(), size_of::<usize>());
Pool::new()
}
struct P2;
fn create_pool2() -> Pool<P2> {
Pool::new()
}
fn main() {
let global_pool1 = create_pool1();
let global_pool2 = create_pool2();
let new_obj1 = global_pool1.allocate();
let new_obj2 = global_pool2.allocate();
// do stuff with objects
global_pool1.free(new_obj1);
global_pool2.free(new_obj2);
global_pool1.free(new_obj2); // oops!, giving back to the wrong pool
global_pool2.free(new_obj1); // oops!, giving back to the wrong pool
}
尝试使用错误的池释放会导致:
error[E0308]: mismatched types
--> zpool\src\main.rs:57:23
|
57 | global_pool1.free(new_obj2); // oops!, giving back to the wrong pool
| ^^^^^^^^ expected struct `P1`, found struct `P2`
|
= note: expected struct `Index<P1>`
found struct `Index<P2>`
链接到游乐场
这可以稍微改进一下,以便借用检查器将强制执行Index
不会超过Pool
,使用:
fn allocate(&self) -> Index<&'_ D> {
self.free_list.borrow_mut()[0] = false;
Index(0, Default::default())
}
因此,如果在 anIndex
还活着的情况下删除了池,则会出现此错误:
error[E0505]: cannot move out of `global_pool1` because it is borrowed
--> zpool\src\main.rs:54:10
|
49 | let new_obj1 = global_pool1.allocate();
| ------------ borrow of `global_pool1` occurs here
...
54 | drop(global_pool1);
| ^^^^^^^^^^^^ move out of `global_pool1` occurs here
...
58 | println!("{}", new_obj1.0);
| ---------- borrow later used here
链接到游乐场
此外,带有Item
API的游乐场链接(仅返回Item
, vs 和Index
)