使用简单资源Allocator结构的生命周期错误

时间:2016-03-26 09:34:29

标签: rust lifetime object-lifetime lifetime-scoping

我正在尝试创建一个简单的分配器,用于从固定的缓冲池中分配和释放缓冲区。

struct AllocatedMemory<'a> {
    mem: &'a mut [u8],
    next: Option<&'a mut AllocatedMemory<'a>>,
}

struct Alloc<'a> {
    glob: Option<&'a mut AllocatedMemory<'a>>,
}

impl<'a> Alloc<'a> {
    fn alloc_cell(mut self: &mut Alloc<'a>) -> &mut AllocatedMemory<'a> {
        let rest: Option<&'a mut AllocatedMemory<'a>>;
        match self.glob {
            Some(ref mut root_cell) => {
                rest = std::mem::replace(&mut root_cell.next, None);
            }
            None => rest = None,
        }
        match std::mem::replace(&mut self.glob, rest) {
            Some(mut root_cell) => {
                return root_cell;
            }
            None => panic!("OOM"),
        }
    }

    fn free_cell(mut self: &mut Alloc<'a>, mut val: &'a mut AllocatedMemory<'a>) {
        match std::mem::replace(&mut self.glob, None) {
            Some(mut x) => {
                let discard = std::mem::replace(&mut val.next, Some(x));
                let rest: Option<&'a mut AllocatedMemory<'a>>;
            }
            None => {}
        }
        self.glob = Some(val);
    }
}

fn main() {
    let mut buffer0: [u8; 1024] = [0; 1024];
    let mut buffer1: [u8; 1024] = [0; 1024];
    {
        let mut cell1: AllocatedMemory = AllocatedMemory {
            mem: &mut buffer1[0..1024],
            next: None,
        };
        let mut cell0: AllocatedMemory = AllocatedMemory {
            mem: &mut buffer0[0..1024],
            next: None,
        };
        let mut allocator = Alloc { glob: None };
        allocator.free_cell(&mut cell1); //populate allocator with a cell
        allocator.free_cell(&mut cell0); //populate allocator with another cell (why does this fail?)

        let mut x = allocator.alloc_cell();
        allocator.free_cell(x);
        let mut y = allocator.alloc_cell();
        let mut z = allocator.alloc_cell();
        allocator.free_cell(y);
        allocator.free_cell(z);
    }
}

错误是

error: `cell0` does not live long enough
     allocator.free_cell(&mut cell0); //populate allocator with another cell (why does this fail?)

当我只删除cell0并且只有cell1可用于我的单元池时,会发生以下错误:

error: allocator does not live long enough
         let mut x = allocator.alloc_cell();
                     ^~~~~~~~~
note: reference must be valid for the block suffix following statement 0 at 46:69...
                                                          next: None};
         let mut cell0 : AllocatedMemory = AllocatedMemory{mem: &mut buffer0[0..1024],
                                                          next: None};
         let mut allocator = Alloc {glob : None};
         allocator.free_cell(&mut cell1); //populate allocator with a cell
         //allocator.free_cell(&mut cell0); //populate allocator with another cell (why does this fail?)

note: ...but borrowed value is only valid for the block suffix following statement 2 at 49:48
         let mut allocator = Alloc {glob : None};
         allocator.free_cell(&mut cell1); //populate allocator with a cell
         //allocator.free_cell(&mut cell0); //populate allocator with another cell (why does this fail?)

         let mut x = allocator.alloc_cell();
         allocator.free_cell(x);
               ...
error: aborting due to previous error

是否有人建议如何修复此代码以便编译并且可能在免费列表中有2个以上的项目?

我想填充一个对数组的引用列表,然后能够弹出它们 - 暂时使用它们并将used / finished值放回到freelist上。

这里的动机是构建一个使用#![nostd]指令的库,因此需要一个分配器接口才能正常运行。

2 个答案:

答案 0 :(得分:2)

问题是你总是使用相同的生命周期cell0。这会强制cell1和{{1}}具有相同的生命周期,这是不可能的,因为必须首先定义一个。如果您仔细阅读错误消息,可以看到它抱怨第二个的生命周期,不包括定义第一个单元格的语句。

我不知道这是否是一个严格执行生命期的错误或错误,或者它是否是生命周期类型系统中固有的(我还没有看到正式的定义)。

我也不知道如何修复它。我通过引入额外的生命周期变量在一些示例代码中修复了类似的问题,但我无法使其适用于您的代码。

答案 1 :(得分:0)

感谢starblue的指针,我决定通过将它们放入结构并将该结构放在堆栈上来强制分配器和单元的生命周期相同。 最终结果如下:

cell.rs:65:19: 65:32 help: run `rustc --explain E0499` to see a detailed explanation
cell.rs:62:19: 62:32 note: previous borrow of `ags.allocator` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `ags.allocator` until the borrow ends

我需要添加sentinel结构,以避免在进行多次分配时双重借用ags.allocator。

glob

将哨兵存储在Alloc中我可以保证在函数返回后我永远不会修改value=vars.get("Jmeter_variable").replaceAll("\\.","-"); vars.put("Updated_variable",value);