MST

星途 面试题库

面试题:Rust指针之智能指针与所有权转移

假设有一个结构体`MyStruct`,内部包含多个不同类型的成员,其中一些成员是堆上分配的数据。请使用`Box`智能指针来管理这些堆上数据的所有权。编写代码实现将`MyStruct`实例的所有权从一个函数转移到另一个函数,并在转移过程中展示如何正确处理内存释放和所有权的交接。另外,解释`Box`指针与普通指针在所有权语义上的区别。
37.7万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

代码实现

// 定义结构体
struct MyStruct {
    data1: i32,
    data2: Box<String>,
}

// 函数1:创建并返回MyStruct实例
fn create_struct() -> MyStruct {
    MyStruct {
        data1: 42,
        data2: Box::new(String::from("Hello, World!")),
    }
}

// 函数2:接收MyStruct实例并处理
fn process_struct(s: MyStruct) {
    println!("data1: {}", s.data1);
    println!("data2: {}", s.data2);
}

fn main() {
    let my_struct = create_struct();
    process_struct(my_struct);
    // 这里my_struct已经转移到process_struct函数中,不能再使用my_struct
}

Box指针与普通指针在所有权语义上的区别

  1. 所有权
    • Box指针:Box拥有其所指向数据的所有权。当Box离开作用域时,它会自动释放其所指向的数据,从而确保内存安全。例如在create_struct函数中创建的Box<String>,当MyStruct实例离开create_struct函数作用域时,Box<String>会自动释放其分配的堆内存。
    • 普通指针:普通指针(如*const T*mut T)不拥有所有权。它们只是指向内存位置,不会自动管理所指向数据的生命周期和内存释放。如果使用普通指针,程序员需要手动管理内存分配和释放,这容易导致内存泄漏等问题。
  2. 内存管理
    • Box指针:Rust的内存管理系统通过Drop trait来管理Box。当Box被销毁时,其实现的Drop trait中的drop方法会被自动调用,从而释放堆上的数据。在上述代码中,当process_struct函数结束时,MyStruct实例被销毁,其中的Box<String>也会自动释放内存。
    • 普通指针:使用普通指针时,由于没有所有权语义,程序员需要自己编写代码来确保内存的正确释放。例如在C/C++中使用delete(对于new分配的内存),如果忘记调用delete,就会造成内存泄漏。
  3. 可移动性
    • Box指针:Box是可移动的,这意味着Box实例可以在函数间传递,将所有权转移给另一个函数。如上述代码中create_struct返回MyStruct实例(其中包含Box),将所有权转移到main函数中,然后main函数又将其所有权转移到process_struct函数。
    • 普通指针:普通指针虽然也可以在函数间传递,但不会涉及所有权的转移。普通指针传递的只是内存地址,而不会改变数据的所有权状态。