将数组分配到运行时已知大小的堆上
Posted
技术标签:
【中文标题】将数组分配到运行时已知大小的堆上【英文标题】:Allocate array onto heap with size known at runtime 【发布时间】:2017-06-02 07:57:43 【问题描述】:在 C++ 中,我可以像这样将一个包含 1000 个 int
s 的数组放入堆中:
int size = 1000;
int* values = new int[size];
delete[] values;
我不知道如何在 Rust 中做同样的事情。
let size = 1000;
let values = Box::new([0; size]) // error: non-constant path in constant expression
据我了解,Rust 强制在编译时知道所有数组的大小,并且不允许您在创建数组时使用表达式。
【问题讨论】:
另见Creating a fixed-size array on heap in Rust、How to allocate arrays on the heap in Rust 1.0 (beta)? 或The Rust Programming Language chapter on vectors。我强烈推荐阅读这本书,因为它涵盖了许多这些介绍性主题。 【参考方案1】:如果数组的大小可以在编译时确定*,您可以使用这样的常量:
const size: usize = 1000; // or: = some_const_fn()
let values = Box::new([0; size])
* 由于 const fn
支持 Rust 1.46 控制流和循环。
【讨论】:
截至本文发布日期,使用版本rustc 1.56.0-nightly (0035d9dce 2021-08-16)
,这实际上是在堆栈上初始化,而不是在堆上。您可以通过将大小增加到堆栈无法容纳的某个巨大值来找出答案。当然,有趣的是,它只会在调试构建时堆栈溢出,但在发布构建时有效。
是的,它首先在堆栈上初始化数组,然后将其移入堆中。在box
syntax 稳定之前,AFAIK 无法直接在堆上初始化变量。
很高兴最终看到一个解决方案,这样我们就不必使用 vec 和 .into_boxed_slice()
作为解决方法(以及调试/发布版本之间的不同行为,老实说甚至不应该发生)【参考方案2】:
Rust 中的数组是固定长度的。如果您想要一个动态大小的数组,请使用Vec
。在这种情况下,最简单的方法是使用 vec!
宏:
let size = 1000;
let values = vec![0; size];
另外,如果您超级担心Vec
是三个字长并且在创建后不需要调整存储空间,您可以显式丢弃内部容量,并带上@ 987654326@ 降到栈上两个字:
let values = values.into_boxed_slice(); // returns a Box<[i32]>.
【讨论】:
你是如何计算出 Vec 和 Box 的默认尺寸的? 一个(装箱的)切片只存储指向切片开头的指针和切片长度作为指针大小的整数。Vec
是一个 growable 数组,因此它为其他元素分配了额外的空间。这意味着Vec
还必须存储已分配缓冲区的容量(至少与长度一样大)。 (所以将 Box<[_]>
视为 2 个指针,将 Vec<_>
视为 3 个指针。)以上是关于将数组分配到运行时已知大小的堆上的主要内容,如果未能解决你的问题,请参考以下文章