将数组分配到运行时已知大小的堆上

Posted

技术标签:

【中文标题】将数组分配到运行时已知大小的堆上【英文标题】:Allocate array onto heap with size known at runtime 【发布时间】:2017-06-02 07:57:43 【问题描述】:

在 C++ 中,我可以像这样将一个包含 1000 个 ints 的数组放入堆中:

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&lt;[_]&gt; 视为 2 个指针,将 Vec&lt;_&gt; 视为 3 个指针。)

以上是关于将数组分配到运行时已知大小的堆上的主要内容,如果未能解决你的问题,请参考以下文章

java - 如何在java中的堆上单独获取所有对象消耗的运行时内存

在C中的堆上分配数组

在运行时更改Jmeter的堆大小

变长 std::array 像

在运行时在堆上分配缓冲区

C99 在运行时如何计算可变长度数组的大小?