我偶然发现了以下场景:
fn compute_values(value: &mut String) {
// the first computation should always work:
let computed_value = String::from("computed value");
// override the default String with the computed value:
*value = computed_value;
// some more code that returns a Result with values or an error message
}
fn main() {
let mut value = String::from("default value");
compute_values(&mut value);
println!("value: {value}")
}
这段代码按照我的预期使用 my 进行编译rustc 1.74.1 (a28077b28 2023-12-04)
并输出value: computed value
,但问题是,该代码是否泄漏内存。
据我了解,*value = computed_value;
进入并且它不再可用(rust编译器确认了这一点,我之后不能computed_value
。)并且在函数作用域结束时不会取消分配。由于这一行有效地将 a 分配给 a ,我猜测所有结构字段都被复制到原始结构的位置。但是,一旦原始包含的引用被覆盖,就无法取消分配 old指向的原始堆内存。由于我没有使用任何不安全的 Rust,并且 Rust 似乎是内存安全的,所以我只能想象原始内存在分配发生之前会自动取消分配,但我找不到有关该主题的任何信息。*value
println!("{computed_value}");
struct String
struct String
&str
&str
我发现以下文章没有回答我的问题:
std::mem::take
名为和std::mem::swap
的答案std::mem::replace
使我相信在这种情况下使用其中之一是必要的。
我还检查了 Rust 官方文档,但没有找到任何内容。
我的问题是:
- 这段代码是否存在内存泄漏?
- 即使替换可变引用的值,非不安全的 Rust 是否应该是内存安全的?
- 是否有关于取消引用分配的任何(官方)文档?
PS:理论上,Rust 可能会进行优化let mut value = String::from("default value");
,使其String
value
指向字符串常量而不是堆上的位置。这样就不需要取消分配内存。但是,当您从 stdin 读取 a 时,整个事情也会起作用value
,然后整个事情必须放置在堆上。
回答
在阅读了 @cyqsimon 的答案(顺便说一句,这很棒)后,我明白这个问题实际上与引用无关,而是在替换值时删除值。有了这个新的见解,我发现这篇 Rustonomicon 文章完全回答了我的问题,并且还讨论了当变量仅被初始化并因此在某些条件下被删除时会发生什么。