doctor 说:
Pub FN new(x:t)->;box 在堆上分配内存,然后将x放入其中.
但"地方"是一个棘手的词.如果我们写下
let arr_boxed = Box::new([0;1000]);
[0;1000]
是否会在堆上就地初始化?
如果我们写下
let arr = [0;1000];
let arr_boxed = Box::new(arr);
编译器是否足够聪明,能够在第一时间初始化堆上的[0;1000]
?
doctor 说:
Pub FN new(x:t)->;box 在堆上分配内存,然后将x放入其中.
但"地方"是一个棘手的词.如果我们写下
let arr_boxed = Box::new([0;1000]);
[0;1000]
是否会在堆上就地初始化?
如果我们写下
let arr = [0;1000];
let arr_boxed = Box::new(arr);
编译器是否足够聪明,能够在第一时间初始化堆上的[0;1000]
?
Box::new()会从一个堆栈复制到另一个堆吗?
有时候.Rust语言不能保证实现这种优化,似乎要由LLVM来解决这个问题. 正因为如此,即使初始化数组也无关紧要 首先,然后传递它,因为对于后端来说,这基本上是相同的事情.
在实践中,业绩将取决于具体情况. 您举的这个例子其实很特别,因为数据都是零:
pub fn foo() -> Box<[i32; 1000]> {
return Box::new([0; 1000]);
}
在我的testing中,编译器能够将其转换为堆数据上的分配+对memset
的调用.
Note:不过,只有在启用了优化的情况下.在调试模式下,它将复制.
另一方面,您可能希望使用已知值来初始化数据:
pub fn bar(v: i32) -> Box<[i32; 1000]> {
return Box::new([v; 1000]);
}
Much to my horror,则编译器决定
初始化堆栈上的整个数据,然后调用memcpy
.(至少它展开了填充循环):).
即使是像[v; 100000]
这样的非常大的数据也会发生这种情况,这会使程序崩溃并导致堆栈溢出.使用编译时已知(非零)的文字,如[64; 100000]
,其行为与此相同.
如果你really想要确定,你可以这样做:
pub fn baz(v: i32) -> Box<[i32; 1000]>{
unsafe {
let b = std::alloc::alloc(
std::alloc::Layout::array::<i32>(1000).unwrap_unchecked()
) as *mut i32;
for i in 0..1000 {
*b.add(i) = v;
}
Box::from_raw(b as *mut [i32; 1000])
}
}
也就是the right thing美元.
baz
的安全版本是:
use std::convert::TryInto;
pub fn quux(v: i32) -> Box<[i32; 1000]> {
let mut b = Vec::with_capacity(1000);
b.extend(std::iter::repeat(v).take(1000));
b.into_boxed_slice().try_into().unwrap()
}
编译器将其优化为quite nicely,实质上是与baz
相同的程序集.
更短的是
vec![v; 1000].into_boxed_slice().try_into::<Box<[i32; 1000]>>().unwrap()
个
这可能是最好的版本.