介绍
在 Rust 中,动态数组( Vec<T>
)的元素指针在某些情况下可能会改变,尤其是当数组增长时。
原因
Vec<T>
是一个动态数组,底层存储是一个连续的内存块。当 Vec
的容量不足以容纳新元素时,它需要分配一块更大的内存并将现有元素复制到新的位置。这个过程称为重新分配(reallocation)。在重新分配后,原来的指针将失效,因为元素被移动到了新的内存位置。
下面是一个示例,说明当 Vec
重新分配时,指针会发生变化:
fn main() {
let mut vec = vec![1, 2, 3];
// 获取第一个元素的指针
let first_element_ptr: *const i32 = &vec[0];
println!("Initial pointer: {:?}", first_element_ptr);
// 添加更多元素,可能会导致重新分配
vec.push(4);
vec.push(5);
// 获取第一个元素的新指针
let new_first_element_ptr: *const i32 = &vec[0];
println!("New pointer after push: {:?}", new_first_element_ptr);
// 比较指针
if first_element_ptr == new_first_element_ptr {
println!("Pointer has not changed");
} else {
println!("Pointer has changed");
}
}
运行结果
在这个示例中,初始指针和新指针可能会不同,特别是当 Vec
进行了重新分配时。输出可能类似于:
Initial pointer: 0x7ffee1c3b870
New pointer after push: 0x7ffee1c3b890
Pointer has changed
解决方案
如果你需要确保指针不会改变,可以预先分配足够的容量,避免重新分配。在下面这个示例中,由于预先分配了足够的容量,指针不会改变。
fn main() {
// 预先分配容量
let mut vec = Vec::with_capacity(10);
vec.push(1);
vec.push(2);
vec.push(3);
// 获取第一个元素的指针
let first_element_ptr: *const i32 = &vec[0];
println!("Initial pointer: {:?}", first_element_ptr);
// 添加更多元素,不会导致重新分配
vec.push(4);
vec.push(5);
// 获取第一个元素的新指针
let new_first_element_ptr: *const i32 = &vec[0];
println!("New pointer after push: {:?}", new_first_element_ptr);
// 比较指针
if first_element_ptr == new_first_element_ptr {
println!("Pointer has not changed");
} else {
println!("Pointer has changed");
}
}
总结
在使用 Vec<T>
时,如果你在添加元素后继续使用指向其元素的指针,必须注意可能的重新分配问题。预先分配足够的容量可以帮助避免指针失效。