如何在函数中初始化堆上的静态结构?

How to initialize static struct on heap in a function?

我有一个全局结构来存储我的对象并具有复杂的行为。 除了数据之外,它还有一个用于对象的全局 id 生成器。他们的工作也需要他们。

use std::sync::{Arc, Mutex};

static mut system_ptr: *mut Box<System> = 0 as *mut Box<System>;

struct System {
    data: Vec<Data>,
    id_mutex: Arc<Mutex<u32>>,
}

impl System {
    fn get_new_id() -> u32 {
        unsafe {
            let s = &mut *system_ptr;
            let mut data = s.id_mutex.lock().unwrap();
            *data += 1;
            *data
        }
    }
}

我现在正在像这样初始化该结构:

fn main() {
    let s = System{data: Vec::new(), id_mutex: Arc::new(Mutex::new(0 as u32))};
    let mut s_box = Box::new(s);
    unsafe {
        system_ptr = &mut s_box as *mut Box<System>;
    }

    // here I have some work with the initialized "System"

}

当我将初始化代码从 main() 移动到某个函数时,Box 被丢弃,我遇到 "use after free" 错误和崩溃。

我尝试使用 &'static 但目前对 Rust 的语义还不够流利,或者这是个坏主意。

无论如何,如何将一些 Box 内存(原始指针)的初始化移动到函数或方法?

编辑:这不是关于单例的问题,而是关于任何堆变量的初始化。马特,感谢您的正确理解!

您可以使用 lazy_static crate 来初始化您的静态变量,然后您就不需要处理原始指针了。

但是如果你想自己处理,你可以这样做:

static mut system_ptr: *mut System = 0 as *mut System;

fn init() {
    let mut system = Box::new(System(Vec::new()));
    unsafe {
        system_ptr = &mut *system;
    }
    std::mem::forget(system);
}

将盒子传递给 std::mem::forget 是故意泄露它,确保它的析构函数永远不会运行。我们没有存储指向 Box 的指针(它本身只是本地堆栈变量中的指针),而是直接存储指向堆上值的指针。

即将发布的 Rust 1.4 版本将有一个 Box::into_raw 函数来为您处理所有这些。如果你升级到 Rust 1.4(目前处于 beta 通道),你可以将上面的代码替换为:

fn init() {
    unsafe {
        system_ptr = Box::into_raw(Box::new(System(Vec::new())));
    }
}