如何在确保指向盒子的指针保持有效的同时更改盒装结构的字段值?

How can I change the value of a field of a boxed struct while making sure the pointer to the box stays valid?

我有以下防锈代码:

pub struct Settings {
  pub vec: Vec<usize>,
  pub index: usize,
}

pub fn add_to_settings_vec(ptr: *mut Settings) {
  // create a box from the pointer
  let boxed_settings = unsafe { Box::from_raw(ptr) };

  // get the value in the box
  let mut settings = *boxed_settings;

  // mutate the value
  settings.vec.push(123);

  // create a new box and get a raw pointer to it so the value isn't deallocated
  Box::into_raw(Box::new(project));
}

我想确保作为函数参数传递的指针保持有效并指向修改后的 Settings 值,即使在将元素添加到未装箱 Settings 的向量之后值。

我想我需要执行以下步骤才能实现我的目标:

这应该是可能的,因为 Settings 值的大小是固定的,据我所知,即使是向量,因为向量在不同的位置增长它的内存。

我已经查看了 https://doc.rust-lang.org/std/boxed/struct.Box.html 上的文档,但我一直无法弄明白。

我也读过有关引脚的信息,但我不知道如何或何时使用它们:https://doc.rust-lang.org/std/pin/index.html

上面的代码是否始终保持传入的指针完好无损?我会很感激解释为什么或为什么不。

如果不是,我如何确保传入的指针保持有效并始终指向内存中相同位置的修改后的 Settings 值?

您可以通过取消引用不安全块中的指针来实现突变:

pub struct Settings {
  pub vec: Vec<usize>,
  pub index: usize,
}

pub fn add_to_settings_vec(ptr: *mut Settings) {
  // mutate the value
  unsafe {(*ptr).vec.push(123)};
}

fn main() {
    let mut s = Settings {
        vec: vec![],
        index: 10,
    };
    
    add_to_settings_vec(&mut s as *mut Settings);
    println!("{:?}", s.vec);
}

Playground

Unbox the value
Modify the settings in place
Make sure that the Settings don't get deallocated

它已经在步骤 (1) 中被解除分配:当您取消引用它时,您将 Settings 结构从 Box 中移出,并在这样做时解除分配了 box。

我不明白你为什么要经历这些乱七八糟的事情(或者为什么你将不安全的指针传递给安全的 non-extern 函数)。

// create a box from the pointer
let mut settings = unsafe { Box::from_raw(ptr) };

// mutate the value
settings.vec.push(123);

settings.leak();

可以正常工作并且不会释放任何东西。尽管如果仅借用指针(它似乎在这里,因为设置永远不会返回。

,则获取 Box 的句柄仍然有风险且没有必要

更好的方法是只借用设置 vec:

let v = unsafe { &mut (*ptr).vec };
v.push(123);

如果您还需要更新索引,则可能是设置结构:

let settings = unsafe { &mut (*ptr) };
settings.vec.push(123);